<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SELECT &#8211; SQLpowered.com</title>
	<atom:link href="https://sqlpowered.com/tag/select/feed/" rel="self" type="application/rss+xml" />
	<link>https://sqlpowered.com</link>
	<description>SQL Server + BI</description>
	<lastBuildDate>Fri, 31 Dec 2021 20:37:26 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://sqlpowered.com/wp-content/uploads/2020/07/FavIcon-e1594067873682-99x100.png</url>
	<title>SELECT &#8211; SQLpowered.com</title>
	<link>https://sqlpowered.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Using MERGE to override OUTPUT clause limitations</title>
		<link>https://sqlpowered.com/using-merge-to-override-output-clause-limitations/</link>
					<comments>https://sqlpowered.com/using-merge-to-override-output-clause-limitations/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Tue, 07 Jul 2020 21:46:39 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[MERGE]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=4148</guid>

					<description><![CDATA[The OUTPUT clause is a very powerful extension of T-SQL included in SQL Server 2005. But from time to time it needs some tweaks or workarounds to get the expected result. One such example is using OUTPUT with INSERT statements. There is a limitation that only columns from the table...]]></description>
										<content:encoded><![CDATA[<p>The OUTPUT clause is a very powerful extension of T-SQL included in SQL Server 2005. But from time to time it needs some tweaks or workarounds to get the expected result. One such example is using OUTPUT with INSERT statements. There is a limitation that only columns from the table to which we are inserting can be used in OUTPUT. I will show you how to override this limitation with a small trick using the MERGE statement added to SQL Server in version 2008.</p>
<p>Let&#8217;s prepare two tables we will play with. One of them will be [dbo].[TargetTable] where data will be inserted from the second table [dbo].[SourceTable].</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DROP TABLE IF EXISTS [dbo].[TargetTable]
DROP TABLE IF EXISTS [dbo].[SourceTable]
GO

CREATE TABLE [dbo].[TargetTable] (
	[ID] INT NOT NULL,
	[Value] NVARCHAR(100)
)
GO

CREATE TABLE [dbo].[SourceTable] (
	[ID] INT NOT NULL,
	[Value] NVARCHAR(100),
	[OtherValue] NVARCHAR(100)
)
GO

INSERT INTO [dbo].[SourceTable]
	( [ID], [Value], [OtherValue] )
	VALUES 
	(1, 'Val1', 'OthVal1' ),
	(2, 'Val2', 'OthVal2' ),
	(3, 'Val3', 'OthVal3' )
GO</pre>
<p>Once everything is prepared we can try the following statement to insert data from the source table to the target table. We would like also to output some columns we will use for review or processing later (if we will use table or table variable as OUTPUT target):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">INSERT INTO [dbo].[TargetTable]
	( [ID],	[Value] )
		OUTPUT [Inserted].[ID], [Inserted].[Value], [src].[OtherValue]
	SELECT 
		[src].[ID], [src].[Value]
	FROM [dbo].[SourceTable] [src]
GO</pre>
<p><img decoding="async" class="alignnone wp-image-4408" src="https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1.png" alt="" width="357" height="25" srcset="https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1.png 672w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1-300x21.png 300w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1-150x10.png 150w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1-360x25.png 360w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1-160x11.png 160w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1-320x22.png 320w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-1-520x36.png 520w" sizes="(max-width: 357px) 100vw, 357px" /></p>
<p>The statement has failed because of the column [src].[OtherValue] isn&#8217;t one of the columns inserted into the target table and therefore it isn&#8217;t allowed to be referenced in the OUTPUT clause.</p>
<p>But what should be done if we really need this column in the output? We can simply get it when MERGE will be used instead of INSERT:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">MERGE INTO [dbo].[TargetTable] [trg]
USING ( SELECT [ID], [Value], [OtherValue]
		FROM [dbo].[SourceTable]
	  ) AS [src] ON 1 = 0
WHEN NOT MATCHED THEN
	INSERT ( [ID],[Value] )
	VALUES ([src].[ID], [src].[Value])
		OUTPUT [Inserted].[ID], [Inserted].[Value], [src].[OtherValue];
GO</pre>
<p><img decoding="async" class="alignnone wp-image-4409" src="https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-2.png" alt="" width="173" height="67" srcset="https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-2.png 392w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-2-300x116.png 300w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-2-150x58.png 150w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-2-360x140.png 360w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-2-160x62.png 160w, https://sqlpowered.com/wp-content/uploads/2020/07/OUTPUT-Clause-With-Outer-Column-Reference-2-320x124.png 320w" sizes="(max-width: 173px) 100vw, 173px" /></p>
<p>MERGE is much flexible to be used together with the OUTPUT clause and is suitable for a lot of special scenarios like this one. INSERT still have its place. Using MERGE everywhere instead of INSERTED isn&#8217;t a good idea. People reading our code will be confused and MERGE has still a lot of <a href="https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/">issues and hidden drawbacks</a> unresolved.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/using-merge-to-override-output-clause-limitations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Specifying FILEGROUP in SELECT * INTO</title>
		<link>https://sqlpowered.com/specifying-filegroup-in-select-into/</link>
					<comments>https://sqlpowered.com/specifying-filegroup-in-select-into/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Thu, 17 Jan 2019 16:23:33 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=2884</guid>

					<description><![CDATA[SQL Server 2017 and SP2 for SQL 2016 bring a small enhancement of SELECT .. INTO clause which offers more possibilities on how to solve some DBA head-scratching situations. It&#8217;s possible to specify FILEGROUP where the new table will be created. Till now it was only in the PRIMARY filegroup...]]></description>
										<content:encoded><![CDATA[<p>SQL Server 2017 and SP2 for SQL 2016 bring a small enhancement of SELECT .. INTO clause which offers more possibilities on how to solve some DBA head-scratching situations. It&#8217;s possible to specify FILEGROUP where the new table will be created. Till now it was only in the PRIMARY filegroup which brings a lot of issues in case the database is divided into more filegroups and primary filegroup stores metadata only with minimal sizing. Running SELECT .. INTO can be used as another option on how to move data between data files and groups. Same for performance optimization like copying data for further processing to filegroup residing on SSD optimized storage.</p>
<p>Syntax:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT *
	INTO dbo.SampleTable_Copy
		ON OtherFilegoup
FROM dbo.SampleTable
GO</pre>
<p>More detail can be found in <a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/select-into-clause-transact-sql?view=sql-server-2017" rel="noopener noreferrer">MSDN</a> or simple demonstration at <a href="https://www.mssqltips.com/sqlservertip/5018/selectinto-enhancements-in-sql-server-2017/" rel="noopener noreferrer">mssqltips.com</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/specifying-filegroup-in-select-into/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Hrátky s Table Value Constructorem</title>
		<link>https://sqlpowered.com/table-value-constructor/</link>
					<comments>https://sqlpowered.com/table-value-constructor/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 01 Oct 2017 07:38:26 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=91</guid>

					<description><![CDATA[Table Value Constructor (TVC) je v SQL Serveru sice již od verze 2008, ale vzhledem k tomu, jak moc si s ním můžeme vyhrát, nebude na škodu si projít pár zajímavých příkladů jeho použití. Jen pro zopakování si připomeňme, že TVC je set jednoho nebo více řádkových výrazů, pomocí kterých...]]></description>
										<content:encoded><![CDATA[<p>Table Value Constructor (TVC) je v SQL Serveru sice již od verze 2008, ale vzhledem k tomu, jak moc si s ním můžeme vyhrát, nebude na škodu si projít pár zajímavých příkladů jeho použití. Jen pro zopakování si připomeňme, že TVC je set jednoho nebo více řádkových výrazů, pomocí kterých můžeme vytvořit virtuální tabulku v jazyce T-SQL a s touto virtuální tabulkou syntakticky dále pracovat jako by se jednalo o běžnou tabulku. Můžeme ji použít v příkazu INSERT, na straně &lt;source table&gt; v MERGE a samozřejmě ve FROM příkazu SELECT.</p>
<p><span id="more-91"></span></p>
<p>Jako první si ukážeme použití TVC s příkazem INSERT, abychom si naplnili naši testovací tabulku:</p>
<pre class="lang:tsql mark:9 decode:true" title="Table value constructor">CREATE TABLE dbo.SampleTable
(
    Id INT NOT NULL,
    Val VARCHAR(20) NULL DEFAULT ('X')
)
GO

INSERT INTO dbo.SampleTable
    VALUES (1, 'A'), (2, 'B'), (3, 'C')
GO

SELECT * FROM dbo.SampleTable
GO</pre>
<p><img decoding="async" class="alignnone size-full wp-image-1441" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-1.png" alt="Playing-with-Table-Value-Constructor-1" width="87" height="77" /></p>
<p>Vidíme, že v rámci jednoho DML příkazu jsem vytvořili tři virtuální řádky, které se nakonec vložili do cílové tabulky.</p>
<p>Kromě explicitního zadání hodnot můžeme využít i DEFAULT pro vložení výchozí hodnoty do sloupce, případně NULL, není-li hodnota známa:</p>
<pre class="lang:tsql mark:2 decode:true">INSERT INTO dbo.SampleTable
    VALUES (4, 'A'), (5, DEFAULT), (6, NULL)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1442" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-2.png" alt="Playing-with-Table-Value-Constructor-2" width="101" height="134" /></p>
<p>Že pomocí TVC vytváří skutečně &#8220;virtuální tabulku&#8221; v rámci daného SQL příkazu snad nejlépe uvidíme, použijeme-li TVC ve FROM jako by se jednalo i jakoukoliv jinou tabulku:</p>
<pre class="lang:tsql mark:2,3,4 decode:true">SELECT * 
FROM (VALUES (1, 'A'), 
             (2, 'B'), 
             (3, 'C')
      ) a (Id, Val)
GO</pre>
<p><img decoding="async" class="alignnone size-full wp-image-1441" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-1.png" alt="Playing-with-Table-Value-Constructor-1" width="87" height="77" /></p>
<p>A nebo ještě lépe, můžeme si pro větší názornost několik TVC mezi sebou propojit:</p>
<pre class="lang:tsql mark:2-4,6-8 decode:true">SELECT * 
FROM (VALUES (1, 'A'), 
             (2, 'B'), 
             (3, 'C')
      ) a (Id, Val)
    INNER JOIN (VALUES (1, 'A'), 
                       (2, 'B'), 
                       (3, 'C')
                ) b (Id, Val) ON a.Id = b.Id
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1443" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-3.png" alt="Playing-with-Table-Value-Constructor-3" width="140" height="77" /></p>
<p>Opravdovou lahůdkou je potom možnost tvořit jednotlivé hodnoty řádku pomocí klasického příkazu SELECT:</p>
<pre class="lang:tsql mark:2-4 decode:true">SELECT * 
FROM (VALUES (1, 'A'), 
             (2, (SELECT 'B')),
             (3, (SELECT TOP(1) LEFT(NAME, 20) FROM sys.objects WHERE NAME LIKE '%%'))
     ) a (Id, Val)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1444" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-4.png" alt="Playing-with-Table-Value-Constructor-4" width="115" height="77" /></p>
<p>TVC je také možné libovolně vzájemně zanořovat:</p>
<pre class="lang:tsql mark:2-4 decode:true">SELECT * 
FROM (VALUES (1, 
              (SELECT Val FROM (VALUES ('A')) b (Val))
              )
      ) a (Id, Val)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1445" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-5.png" alt="Playing-with-Table-Value-Constructor-5" width="87" height="39" /></p>
<p>Stejně tak můžeme TVC dotazovat jako klasikou tabulku v různých kombinacích SELECT příkazu:</p>
<pre class="lang:tsql mark:2 decode:true">SELECT 
    (SELECT TOP(1) Id FROM (VALUES (1, 'A'), (2, 'B'), (3, 'C')) a (Id, Val) ORDER BY Val DESC) Id
FROM (SELECT 1 a) a
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1446" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-6.png" alt="Playing-with-Table-Value-Constructor-6" width="57" height="39" /></p>
<p>Co ovšem již udělat nemůže je, pokusit se použít TVC s jinými DML příkazy než INSERT, tedy s UPDATE nebo DELETE, případně na &lt;target table&gt; straně příkazu MERGE:</p>
<pre class="lang:tsql mark:4-6 decode:true">UPDATE a
	SET Id = 5
--SELECT * 
FROM (VALUES (1, 'A'), 
             (2, 'B'), 
             (3, 'C')
      ) a (Id, Val)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1449" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-7.png" alt="Playing-with-Table-Value-Constructor-7" width="679" height="29" /></p>
<p>To vše samozřejmě platí pouze tehdy, pokoušíme-li se měnit data vytvořená pomocí TVC. Využít TVC následujícím způsobem možné je, neboť zde je součástí SELECT příkazu:</p>
<pre class="lang:tsql mark:5 decode:true">UPDATE st
	SET Val = 'UPD_' + CAST(a.Id AS VARCHAR(10))
--SELECT *
FROM dbo.SampleTable st
	INNER JOIN (VALUES(1), (2)) a (Id) on st.ID = a.ID
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1450" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-8.png" alt="Playing-with-Table-Value-Constructor-8" width="108" height="76" /></p>
<p>Pokud jsem hovořili o použití TVC s příkazem MERGE na místě &lt;source table&gt;, vypadá náš příklad takto:</p>
<pre class="lang:tsql mark:3-6 decode:true">MERGE INTO dbo.SampleTable trg
USING 
	(VALUES
		(3, 'MRG'),
		(4, 'NEW')
	) AS src (Id, Val)
	ON trg.Id = src.Id
WHEN NOT MATCHED THEN
	INSERT (Id, Val)
	VALUES (src.Id, src.Val)
WHEN MATCHED THEN UPDATE 
	SET trg.Val = src.Val;
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1451" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-9.png" alt="Playing-with-Table-Value-Constructor-9" width="99" height="58" /></p>
<p>Na co nesmíme zapomenout při využít TVC ve FROM jsou pravidla pro pojmenování sloupců u odvozených tabulek: První příkaz skončí s chybou, protože jsem zapomněli pojmenovat sloupce. Jak to napravit ukazuje druhý příkaz:</p>
<pre class="lang:tsql decode:true">SELECT * FROM (VALUES (1, 'A')) a
GO

SELECT * FROM (VALUES (1, 'A')) a (Id, Val)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1453" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-10.png" alt="Playing-with-Table-Value-Constructor-10" width="350" height="61" /></p>
<p>Pozor je třeba dát i na to, že DEFAULT můžeme použít pouze tehdy, vkládáme-li data do tabulky v rámci INSERT příkazu, nikoliv v pouhém SELECTu:</p>
<pre class="lang:tsql decode:true">SELECT * FROM (VALUES (1, DEFAULT)) a (Id, Val)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1454" src="https://sqlpowered.com/wp-content/uploads/2013/03/Playing-with-Table-Value-Constructor-11.png" alt="Playing-with-Table-Value-Constructor-11" width="315" height="32" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/table-value-constructor/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Používání CASE ve WHERE</title>
		<link>https://sqlpowered.com/pouzivani-case-ve-where/</link>
					<comments>https://sqlpowered.com/pouzivani-case-ve-where/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Mon, 24 Apr 2017 20:40:01 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=610</guid>

					<description><![CDATA[Pokud vynecháme případné záludnosti, které nám může přinést použití příkazu CASE ve WHERE podmínce, je to někdy nadmíru šikovná pomůcka, která najde své využití především v různých uložených procedurách používaných jako datové zdroje pro Reporting Services reporty, případně jako chytrá pomůcka aplikaci pro získání filtrovaných datových setů pro gridy a...]]></description>
										<content:encoded><![CDATA[<p>Pokud vynecháme případné záludnosti, které nám může přinést použití příkazu CASE ve WHERE podmínce, je to někdy nadmíru šikovná pomůcka, která najde své využití především v různých uložených procedurách používaných jako datové zdroje pro Reporting Services reporty, případně jako chytrá pomůcka aplikaci pro získání filtrovaných datových setů pro gridy a různé jiné ovládací prvky.</p>
<p>Jednoduchá ukázka jak na to syntakticky je zde:</p>
<pre class="lang:tsql decode:true ">SELECT *
FROM dbo.TestTable
WHERE Id = @Id AND
      (
       CASE
            WHEN @Type = 'D' AND Cislo = @Id2 THEN 1
            WHEN @Type = 'L' AND Cislo = @Id2 THEN 1
            ELSE 0
       END
      ) = 1</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/pouzivani-case-ve-where/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Spojování Common Table Expressions</title>
		<link>https://sqlpowered.com/spojovani-common-table-expressions/</link>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Wed, 24 Jun 2015 06:57:11 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=702</guid>

					<description><![CDATA[Common Table Expressions (CTE), dočasné pojmenované sety, představují mocný nástroj pro řešení nejrůznějších situací. Kromě jejich nejběžnějšího použití v případě, kdy potřebujeme rekurzivně procházet množinu dat, patří k jejich další zajímavé silné vlastnosti možnost spojování více CTE za sebou. V článku si ukážeme, jaký je syntaktický zápis a praktickou aplikaci....]]></description>
										<content:encoded><![CDATA[<p>Common Table Expressions (CTE), dočasné pojmenované sety, představují mocný nástroj pro řešení nejrůznějších situací. Kromě jejich nejběžnějšího použití v případě, kdy potřebujeme rekurzivně procházet množinu dat, patří k jejich další zajímavé silné vlastnosti možnost spojování více CTE za sebou. V článku si ukážeme, jaký je syntaktický zápis a praktickou aplikaci. Podíváme se i na některá negativa z pohledu výkonu.<span id="more-702"></span></p>
<p>Více CTE spojíme k sobě jednoduše pomocí čárky, kterou je od sebe oddělíme dvě nebo více definic. Klauzule WITH se zapisuje pouze u první definice. Každá další definice může může přistupovat k datovému setu vytvořenému v definici předcházejí. Reference v opačném směru nejsou možné.</p>
<p>Celou funkcionalitu si ukážeme na následujícím jednoduchém skriptu:</p>
<pre class="lang:tsql decode:true">WITH 
CTE1 (N) 
AS (
     SELECT 1 
     UNION ALL
     SELECT 2
   ),
CTE2 (N) 
AS (
      SELECT c1.N 
      FROM CTE1 c1 
		CROSS JOIN CTE1 c2 
    )
SELECT * 
FROM CTE2
    INNER JOIN CTE1 ON CTE1.N = CTE2.N</pre>
<p>V první kroku jsme vytvořili set CTE1, který obsahuje dva řádky s hodnotami 1 a 2, spojenými pomocí UNION ALL. Definici jsme uzavřeli závorkou a čárkou, za níž jsme vytvořili definici CTE2, která již může používat předtím vytvořený set CTE1. V posledním kroku jsme v SELECT dotazu vypsali řádky ze setu CTE2, ale stejně tak dobře můžeme referencovat kterýkoliv výše definovaný set, jak v našm příkladu ukazuje INNER JOIN na CTE1.</p>
<p>Ačkoliv syntaktický zápis svádí k tomu, abychom předpokládali, že SQL Server uvažuje logicky a nejdříve vykoná dotaz pro CTE1, poté nad výsledkem dotaz pro CTE2, atd., ve většině případů tomu tak není a můžeme být opravdu překvapeni, co optimalizátor dotazů předvádí. Vše si ukážeme na následujících příkladech:</p>
<p>Nejprve si vytvoříme tabulku #TestData a naplníme ji testovacími daty:</p>
<pre class="lang:tsql decode:true">CREATE TABLE #TestTable (ID INT NOT NULL,
			 VALUE NVARCHAR(128))

INSERT INTO #TestTable (ID, VALUE)
	SELECT TOP (10000) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)), v1.name
	FROM spt_values v1
		CROSS JOIN spt_values v2
	WHERE v1.name like '%PROCEDURE%'
	ORDER BY NEWID()
GO</pre>
<p>Nyní budeme zkoušet jednotlivé kombinace CTE a sledovat exekuční plány. Ve všech příkladech přidáváme nakonec query hint MAXDOP(1), abychom se pro zjednodušení vyhnuli paralelnímu exekučním plánu.</p>
<pre class="lang:tsql decode:true">WITH CTE1 AS
(
	SELECT * FROM #TestTable WHERE VALUE LIKE '%PROCEDURE%'
),
CTE2 AS
(
	SELECT * FROM CTE1
),
CTE3 AS
(
	SELECT * FROM CTE2
)
SELECT * FROM CTE1
UNION ALL
SELECT * FROM CTE2 
UNION ALL
SELECT * FROM CTE3
OPTION(MAXDOP 1)
GO</pre>
<p>V tomto dotazu nejprve v CTE1 filtrujeme data z #TestTable a dále tento výsledek referencujeme v CTE2 a CTE2 opět v CTE3. Očekávali bychom, že SQL Server vykoná jedno čtení z tabulky #TestData v rámci CTE1, a že CTE2 a CTE3 budou pouze syntaktickým odpadem. Exekuční plán však vypadá takto:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1299" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan1.png" alt="MultipleCTE_ExxecutionPlan1" width="381" height="253" /></p>
<p>SQL Server ve skutečnosti četl zdrojovou tabulku třikrát, a pokud se podíváme na detail jednotlivých Table Scan operátorů, vidíme, že jsou identické a všechny obsahují podmínku WHERE:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1300" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan5.png" alt="MultipleCTE_ExxecutionPlan5" width="260" height="142" /></p>
<p>Nyní změníme náš příklad a budeme se dotazovat pouze na data z CTE3:</p>
<pre class="lang:tsql decode:true ">WITH CTE1 AS
(
	SELECT * FROM #TestTable WHERE VALUE LIKE '%PROCEDURE%'
),
CTE2 AS
(
	SELECT * FROM CTE1
),
CTE3 AS
(
	SELECT * FROM CTE2
)
SELECT * FROM CTE3
OPTION(MAXDOP 1)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1298" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan2.png" alt="MultipleCTE_ExxecutionPlan2" width="210" height="75" /></p>
<p>Nyní nás již optimalizátor nezklamal a vidíme, že scanoval #TestTable pouze jednou. Správně dovodil, že CTE2 a CTE3 na samotném výsledku nic nemění. Stejně chytře se optimalizátor vypořádá i s případným dalším filtrování CTE1 v CTE2 a CTE3.</p>
<p>Pokud ovšem například v CTE3 sáhneme po komplexnější operaci, může nás optimalizátor opět poněkud překvapit:</p>
<pre class="lang:tsql decode:true">WITH CTE1 AS
(
	SELECT * FROM #TestTable WHERE VALUE LIKE '%PROCEDURE%'
),
CTE2 AS
(
	SELECT * FROM CTE1
),
CTE3 AS
(
	SELECT CTE1.ID, CTE2.VALUE FROM CTE2 INNER JOIN CTE1 ON CTE1.ID = CTE2.ID
)
SELECT * FROM CTE3
OPTION(MAXDOP 1)
GO
</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1297" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan3.png" alt="MultipleCTE_ExxecutionPlan3" width="365" height="172" /></p>
<p>Z exekučního plánu vidíme, že sice došlo k eliminaci CTE2, ale pro provedení joinu SQL Server musel provést opravdu dva scany stejné tabulky, aby byl schopen vytvořit výslednou sadu řádků.</p>
<p>Následující dva příklady nám ukážou, že někdy je optimalizátor neobyčejně chytrý:</p>
<pre class="lang:tsql decode:true ">WITH CTE1 AS
(
	SELECT * FROM #TestTable WHERE VALUE LIKE '%PROCEDURE%'
),
CTE2 AS
(
	SELECT COUNT(*) Cnt FROM CTE1
)
SELECT * FROM CTE2
OPTION(MAXDOP 1)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1301" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan6.png" alt="MultipleCTE_ExxecutionPlan6" width="513" height="75" /></p>
<p>Vidíme pouze jeden Table Scan, tedy očekávaný výsledek. Nyní udělejme drobnou úpravu a přidejme CTE3:</p>
<pre class="lang:tsql decode:true ">WITH CTE1 AS
(
	SELECT * FROM #TestTable WHERE VALUE LIKE '%PROCEDURE%'
),
CTE2 AS
(
	SELECT COUNT(*) Cnt FROM CTE1
),
CTE3 AS
(
	SELECT COUNT(*) Cnt FROM CTE2
)
SELECT * FROM CTE3
OPTION(MAXDOP 1)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1296" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan4.png" alt="MultipleCTE_ExxecutionPlan4" width="522" height="74" /></p>
<p>Výsledek je opravdu překvapivý: optimalizátor provedl logickou eliminaci, kdy správně určil, že výsledek vždy bude 1, protože CTE3 se dotazuje do CTE2, která vždy vrátí pouze jeden řádek. Není tedy vůbec třeba přistupovat ke zdrojovým datům a výsledek dotazu lze určit pouze jeho logickou analýzou.</p>
<p>Poslední zajímavé chování nám ukazuje následující dotaz:</p>
<pre class="lang:tsql decode:true">WITH CTE1 AS
(
	SELECT * FROM #TestTable WHERE VALUE LIKE '%PROCEDURE%'
),
CTE2 AS
(
	SELECT * FROM CTE1 WHERE VALUE LIKE '%filter%'
),
CTE3 AS
(
	SELECT * FROM CTE2
)
SELECT * 
FROM CTE1
	INNER JOIN CTE3 ON CTE3.ID = CTE1.ID
OPTION(MAXDOP 1)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1297" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan3.png" alt="MultipleCTE_ExxecutionPlan3" width="365" height="172" /></p>
<p>Vidíme opět dva Table Scan operátory, ale u druhého z nich nám predikát ukazuje, že SQL  Server složil obě podmínky do jedné pomocí AND:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1302" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan7.png" alt="MultipleCTE_ExxecutionPlan7" width="286" height="64" /></p>
<p>Z výše uvedeného je zřejmé, že CTE (mimo její rekurzivní funkce) je pouze syntaktickým konstruktem a při jejím spojování nelze o jednotlivých CTE uvažovat jako o dočasném datovém setu, který SQL Server vytváří někde na pozadí a následně používá pro další zpracování. Ve většině případů můžeme dosáhnout stejného nebo lepší výkonu konvenčním zápisem, např. náš poslední dotaz můžeme zapsat i takto:</p>
<pre class="lang:tsql decode:true">SELECT ID, VALUE
FROM #TestTable 
WHERE VALUE LIKE '%PROCEDURE%' AND VALUE LIKE '%filter%'
GO</pre>
<p>Odměnou je nám jednoduchý exekuční plán přesně dle očekávání:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1303" src="https://sqlpowered.com/wp-content/uploads/2015/06/MultipleCTE_ExxecutionPlan8.png" alt="MultipleCTE_ExxecutionPlan8" width="205" height="77" /></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>LIKE: ESCAPE a COLLATE</title>
		<link>https://sqlpowered.com/like/</link>
					<comments>https://sqlpowered.com/like/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 17 May 2015 06:11:49 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=660</guid>

					<description><![CDATA[Jak používat klauzuli LIKE ví asi každý. Ale u mladších kolegů se často setkávám s tím, že si neumí poradit s jejím využitím v prostředí s různými kolacemi a nebo nevědí, jak dosáhnout správného výsledku v případě, že hledají řetězec, který obsahuje některý se speciálních znaků, např. %. COLLATE Řešení...]]></description>
										<content:encoded><![CDATA[<p>Jak používat klauzuli LIKE ví asi každý. Ale u mladších kolegů se často setkávám s tím, že si neumí poradit s jejím využitím v prostředí s různými kolacemi a nebo nevědí, jak dosáhnout správného výsledku v případě, že hledají řetězec, který obsahuje některý se speciálních znaků, např. %.</p>
<h4>COLLATE</h4>
<p>Řešení problémů s výběrem správné kolace je jednoduché: stačí využít COLLATE direktivu stejně jako v jakýchkoliv jiných případech, např. když  joinujeme sloupce napříč databázemi s rozdílnou kolací:</p>
<pre class="lang:tsql decode:true">SELECT * 
FROM dbo.SampleTable 
WHERE Col1 LIKE '[a-d]%' COLLATE Latin1_General_BIN</pre>
<p>Takto jednoduše můžeme u LIKE zařídit třeba hledání všech řetězců, které začínají na písmena a až d, což pro anglickou kolaci znamená písmena a,b,c,d, kdežto pro českou a,b,c,č,d.</p>
<h4>ESCAPE</h4>
<p>ESCAPE direktivu budeme potřebovat vždy, když chceme hledat řetězce, které obsahují některé speciální znaky, které běžně využíváme v podmínce LIKE pro nastavení jejího chování, např. %, _ , [ atd.</p>
<p>ESCAPE funguje tak, že pomocí něho můžeme určit, že námi zvolený znak bude využíván jako značka, kterou umístíme před speciální znaky a tím je označíme tak, že již nebudou plnit svoji speciální funkci, ale budou považovány za běžný řetězec.<br />
V příkladu níže vidíme, že jsme zvolili zpětné lomítko &#8216;/&#8217; jako separátor speciálních znaků.<br />
Nebudeme tedy hledat všechny řetězce začínající na &#8216;Novak&#8217;, tedy např. Nováková, ale místo toho hledáme všechny výskyty řetězce &#8216;Novak%&#8217;.</p>
<pre class="lang:tsql decode:true">SELECT * FROM dbo.Person WHERE Surname LIKE 'Novák/%' ESCAPE '/'</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/like/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>COUNT() a eliminace NULL hodnot</title>
		<link>https://sqlpowered.com/count-a-eliminace-null-hodnot/</link>
					<comments>https://sqlpowered.com/count-a-eliminace-null-hodnot/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Mon, 23 Feb 2015 21:09:28 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=536</guid>

					<description><![CDATA[Agregační funkce v SQL serveru ignorují hodnoty NULL. V praxi to znamená, že pokud agregujeme data ve sloupcích a některé řádky obsahují NULL hodnoty, tyto hodnoty se do naší agregace nezapočítají. Pro funkce typu SUM() je to očekávané chování, ale již ne tak pro AVG() nebo COUNT(). Funkce COUNT() se...]]></description>
										<content:encoded><![CDATA[<p>Agregační funkce v SQL serveru ignorují hodnoty NULL. V praxi to znamená, že pokud agregujeme data ve sloupcích a některé řádky obsahují NULL hodnoty, tyto hodnoty se do naší agregace nezapočítají. Pro funkce typu SUM() je to očekávané chování, ale již ne tak pro AVG() nebo COUNT(). Funkce COUNT() se chová ještě více specificky, protože můžeme kromě sloupce (jako u jiných funkcí) využít i asterix  &#8211; COUNT(*). K čemu tento rozdíl vede si ukážeme dále v článku.<span id="more-536"></span></p>
<p>Vytvoříme si testovací tabulku s jedním sloupcem ID, do kterého vyplníme pět hodnot, z nichž jedna je NULL:</p>
<pre class="lang:tsql decode:true">CREATE TABLE [dbo].[SampleTable](
 [ID] [int] NULL
) ON [PRIMARY]
GO

INSERT INTO [dbo].[SampleTable] 
 ([ID])
 SELECT 1 UNION ALL
 SELECT 2 UNION ALL
 SELECT 3 UNION ALL
 SELECT NULL UNION ALL
 SELECT 5
GO</pre>
<p>Nyní spustíme tyto dva dotazy a porovnáme jejich výstup:</p>
<pre class="lang:tsql decode:true">SELECT COUNT(*) FROM dbo.SampleTable

SELECT COUNT(ID) FROM dbo.SampleTable
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1354" src="https://sqlpowered.com/wp-content/uploads/2015/02/NULL_values_ignored_in_COUNT.png" alt="NULL_values_ignored_in_COUNT" width="65" height="87" /></p>
<p>První dotaz s COUNT(*) nám vrátil pět řádků, protože COUNT() s aterixem (*) nám vrací počet řádků přes všechny sloupce = celou tabulku. COUNT(ID) provádí agregaci nad konkrétním sloupcem a zde se chová jako jiné agregační funkce a hodnoty NULL ignoruje. Proto je v prvím případě výsledek 5 (celkový počet řádků v tabulce) a ve druhém 4 (počet NOT NULL hodnot ve sloupci ID).</p>
<p>Že se nejedná o příliš intuitivní chování, ale hlavně se nejedná o přesnou implementaci ANSI standardu SQL, nás SQL Server upozorní v okně zpráv, kde se po vykonání druhého dotazu zobrazí následující varování:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1355" src="https://sqlpowered.com/wp-content/uploads/2015/02/NULL_values_ignored_in_COUNT_2.png" alt="NULL_values_ignored_in_COUNT_2" width="519" height="106" /></p>
<p>Varování můžeme potlačit nastavením SET <a href="https://msdn.microsoft.com/en-us/library/ms190368.aspx" target="_blank" rel="noopener noreferrer">ANSI_WARNINGS</a> { ON | OFF }, které je ve výchozím nastavením ON, případně lze varování potlačit pro celý server a všechna připojení pomocí <a href="http://msdn.microsoft.com/en-us/library/ms188787.aspx" target="_blank" rel="noopener noreferrer">sp_configure</a>. Změnu tohoto nastavení však nezle doporučit a pro řadu operací je vyžadováno nastavení SET_ANSI_WARNINGS na výchozí hodnotu ON.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/count-a-eliminace-null-hodnot/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CTE with multiple anchors</title>
		<link>https://sqlpowered.com/common-table-expression-with-multiple-anchors/</link>
					<comments>https://sqlpowered.com/common-table-expression-with-multiple-anchors/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Tue, 03 Feb 2015 20:53:03 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=515</guid>

					<description><![CDATA[Common Table Expression (CTE) offers a lot of options on how to play with it. One of them is using recursion with an anchor which is in the standard scenario one row. But we can have a more complex anchor: instead of one row, it can be i.e. union on...]]></description>
										<content:encoded><![CDATA[<p><a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-2017" rel="noopener noreferrer">Common Table Expression</a> (CTE) offers a lot of options on how to play with it. One of them is using recursion with an anchor which is in the standard scenario one row. But we can have a more complex anchor: instead of one row, it can be i.e. union on more rows creating new anchor dataset.</p>
<p>How that works is presented in this simple example:</p>
<pre class="lang:tsql decode:true">;WITH cte(Value)
AS
(
    SELECT CONVERT(VARCHAR(1000),'Anchor1_') 
    UNION ALL
    SELECT CONVERT(VARCHAR(1000),'Anchor2_') 
    UNION ALL
    SELECT CONVERT(VARCHAR(1000), Value + 'x') 
    FROM cte
    WHERE LEN(Value) &lt; 15    
)
SELECT *
FROM cte
ORDER BY LEN(Value)</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-579" src="https://sqlpowered.com/wp-content/uploads/2015/06/CTEwithMultipleAnchors.jpg" alt="CTEwithMultipleAnchors" width="131" height="324" /></p>
<p>We have created two anchor rows: Anchor1_ and Anchor2_. Then we are running recursive iteration over it adding an &#8216;x&#8217; in every step until the total length of the string is 15. Instead of UNION ALL we can use any kind of option on how to create a multirow anchor dataset like VALUES() or standard SELECT statement.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/common-table-expression-with-multiple-anchors/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Examples of TOP syntax</title>
		<link>https://sqlpowered.com/top-syntax-examples/</link>
					<comments>https://sqlpowered.com/top-syntax-examples/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Wed, 21 May 2014 14:41:52 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SELECT]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=339</guid>

					<description><![CDATA[This article is just a short summary of TOP clause variants we can use. Especially the last one with a subquery isn&#8217;t so common and can be something new for you. Consider official documentation for more details on TOP usage and if you have any other interesting example don&#8217;t hesitate...]]></description>
										<content:encoded><![CDATA[<p>This article is just a short summary of TOP clause variants we can use. Especially the last one with a subquery isn&#8217;t so common and can be something new for you. Consider official <a href="https://docs.microsoft.com/en-us/sql/t-sql/queries/top-transact-sql?view=sql-server-ver15" target="_blank" rel="noopener noreferrer">documentation</a> for more details on TOP usage and if you have any other interesting example don&#8217;t hesitate to put it in comments.</p>
<pre class="lang:tsql decode:true ">-- Using constant value
SELECT TOP 10 * -- (10)
FROM sys.messages
GO

-- Using percents
SELECT TOP 10 PERCENT * -- (10) PERCENT
FROM sys.messages
GO

-- Using variable
DECLARE @Cnt INT
SET @Cnt = 10

SELECT TOP (@Cnt) * FROM sys.messages
SELECT TOP (@Cnt) PERCENT * FROM sys.messages
GO

-- Using subquery
SELECT TOP (SELECT COUNT(*)/10 FROM sys.messages) *
FROM sys.messages</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/top-syntax-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
