<?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>functions &#8211; SQLpowered.com</title>
	<atom:link href="https://sqlpowered.com/tag/functions/feed/" rel="self" type="application/rss+xml" />
	<link>https://sqlpowered.com</link>
	<description>SQL Server + BI</description>
	<lastBuildDate>Fri, 31 Dec 2021 20:33:10 +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>functions &#8211; SQLpowered.com</title>
	<link>https://sqlpowered.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>FORMATMESSAGE() maximum output length</title>
		<link>https://sqlpowered.com/formatmessage-maximum-output-length/</link>
					<comments>https://sqlpowered.com/formatmessage-maximum-output-length/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sun, 26 Dec 2021 21:09:49 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=5215</guid>

					<description><![CDATA[FORMATMESSAGE() is a quite useful competitor to RAISERROR() function, mainly in the case we won&#8217;t print the message directly but prepare it for further processing. One important limitation is there we must remember: The maximum output character length is limited to 2047 characters. When the final message is longer then...]]></description>
										<content:encoded><![CDATA[<p><a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/formatmessage-transact-sql?view=sql-server-ver15" target="_blank" rel="noopener">FORMATMESSAGE()</a> is a quite useful competitor to <a href="https://docs.microsoft.com/en-us/sql/t-sql/language-elements/raiserror-transact-sql?view=sql-server-ver15" target="_blank" rel="noopener">RAISERROR()</a> function, mainly in the case we won&#8217;t print the message directly but prepare it for further processing. One important limitation is there we must remember: The maximum output character length is limited to 2047 characters. When the final message is longer then it will be shortened to 2044 characters and three dots ellipsis is added to the end of the message string.</p>
<p>Let&#8217;s see it in the action:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Message NVARCHAR(MAX) = 'String1:%s, String2:%s, String3:%s'
DECLARE @StringA NVARCHAR(MAX)
DECLARE @StringB NVARCHAR(MAX)
DECLARE @StringC NVARCHAR(MAX)

SET @StringA = REPLICATE('A', 1000)
SET @StringB = REPLICATE('B', 1000)
SET @StringC = REPLICATE('C', 1000)

-- print the message
PRINT FORMATMESSAGE(@Message, @StringA, @StringB, @StringC)

-- get message string length
SELECT LEN(FORMATMESSAGE(@Message, @StringA, @StringB, @StringC))

-- compare to RAISERROR()
RAISERROR(@Message, 10, 1, @StringA, @StringB, @StringC)
GO</pre>
<p><img decoding="async" class="alignnone wp-image-5224" src="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_2.png" alt="" width="146" height="17" srcset="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_2.png 291w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_2-150x18.png 150w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_2-160x19.png 160w" sizes="(max-width: 146px) 100vw, 146px" /></p>
<p><img decoding="async" class="alignnone wp-image-5223" src="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length.png" alt="" width="370" height="76" srcset="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length.png 673w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length-300x62.png 300w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length-150x31.png 150w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length-360x74.png 360w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length-160x33.png 160w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length-320x66.png 320w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length-520x107.png 520w" sizes="(max-width: 370px) 100vw, 370px" /></p>
<p>It is pretty well visible how the message was shortened from expected more than 3k characters to the 2044 characters maximum and ellipsis added. RAISERROR() returns exactly the same result.</p>
<p>Why does this matter? Consider an example where you would like to build i.e. JSON string and you will decide to build individual keys like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">USE [msdb]
GO

DECLARE @Pattern NVARCHAR(MAX)

SET @Pattern = '{"Table_Id": %i, "Table_Name": "%s", "Columns": [ %s ] }'

SELECT 
	[a].[JSON_Row], LEN([a].[JSON_Row]) Characters
FROM (
		SELECT 
			FORMATMESSAGE(@Pattern, t.[object_id], t.[name], STRING_AGG('{ "Name": "' + c.[name] + '", "Datatype": "' + tp.[name] + '" }', ',')) JSON_Row
		FROM sys.[tables] t
			INNER JOIN sys.[columns] c ON [c].[object_id] = [t].[object_id]
			INNER JOIN sys. tp ON [tp].[system_type_id] = [c].[system_type_id] AND [tp].[user_type_id] = [c].[user_type_id]
		GROUP BY t.[object_id], t.[name]
	) a
ORDER BY Characters DESC
GO</pre>
<p><img fetchpriority="high" decoding="async" class="alignnone wp-image-5226" src="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3.png" alt="" width="609" height="122" srcset="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3.png 1587w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-300x60.png 300w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-1024x205.png 1024w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-150x30.png 150w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-768x154.png 768w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-1536x308.png 1536w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-360x72.png 360w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-160x32.png 160w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-320x64.png 320w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-520x104.png 520w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-720x144.png 720w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-980x196.png 980w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_3-1320x264.png 1320w" sizes="(max-width: 609px) 100vw, 609px" /></p>
<p>Two rows marked exceeded the maximum 2044 allowed length for FORMATMESSAGE() output and their value was silently shortened in the background and if you will try to parse the JSON later you might get an error but not all the time, only when you hit the invalid part of the JSON (which makes things getting much worst then it looks like):</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @Pattern NVARCHAR(MAX)

SET @Pattern = '{"Table_Id": %i, "Table_Name": "%s", "Columns": [ %s ] }'

SELECT 
	-- JSON_VALUE([a].[JSON_Row], '$.Table_Id') -- This will work
	JSON_VALUE([a].[JSON_Row], '$.Columns') -- This will fail
FROM (
		SELECT 
			FORMATMESSAGE(@Pattern, t.[object_id], t.[name], STRING_AGG('{ "Name": "' + c.[name] + '", "Datatype": "' + tp.[name] + '" }', ',')) JSON_Row
		FROM sys.[tables] t
			INNER JOIN sys.[columns] c ON [c].[object_id] = [t].[object_id]
			INNER JOIN sys. tp ON [tp].[system_type_id] = [c].[system_type_id] AND [tp].[user_type_id] = [c].[user_type_id]
		GROUP BY t.[object_id], t.[name]
	) a
--WHERE LEN([a].[JSON_Row]) &lt;= 2047 -- This will remove invalid rows and keep it finish
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone wp-image-5228" src="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4.png" alt="" width="639" height="33" srcset="https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4.png 1143w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-300x15.png 300w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-1024x53.png 1024w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-150x8.png 150w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-768x40.png 768w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-1140x59.png 1140w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-360x19.png 360w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-160x8.png 160w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-320x17.png 320w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-520x27.png 520w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-720x37.png 720w, https://sqlpowered.com/wp-content/uploads/2021/12/FORMATMESSAGE_Max_Length_4-980x51.png 980w" sizes="auto, (max-width: 639px) 100vw, 639px" /></p>
<p>It&#8217;s more than obvious that ignoring basic facts highlighted in the official SQL Server documentation may let you scratch the head for several hours:)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/formatmessage-maximum-output-length/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>APPROX_COUNT_DISTINCT()</title>
		<link>https://sqlpowered.com/approx_count_distinct/</link>
					<comments>https://sqlpowered.com/approx_count_distinct/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Fri, 20 Sep 2019 21:50:01 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=3309</guid>

					<description><![CDATA[APPROX_COUNT_DISTINCT() is a nice new function announced currently to be in public preview for Azure. Being well known for Oracle users is now joining (like many other things:)) also the Microsoft world. This function is designed to provide aggregations across large data sets where responsiveness is more critical than absolute...]]></description>
										<content:encoded><![CDATA[<p><a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/approx-count-distinct-transact-sql?view=sql-server-ver15" rel="noopener noreferrer">APPROX_COUNT_DISTINCT()</a> is a nice new function announced currently to be in public preview for Azure. Being well known for Oracle users is now joining (like many other things:)) also the Microsoft world.</p>
<p>This function is designed to provide aggregations across large data sets where responsiveness is more critical than absolute precision. It evaluates an expression for each row in a group and returns the approximate number of unique non-null values in a group.</p>
<p>It accepts an expression of any type, except <strong>image</strong>, <strong>sql_variant</strong>, <strong>ntext</strong>, or <strong>text</strong>.</p>
<p>Internally it&#8217;s optimized for use in big data scenarios for the following conditions:</p>
<ul>
<li>Access to data sets that are millions of rows or higher and</li>
<li>Aggregation of a column or columns that have many distinct values</li>
</ul>
<p>The function implementation guarantees up to a 2% error rate within a 97% probability using the <a href="https://en.wikipedia.org/wiki/HyperLogLog" data-linktype="external">HyperLogLog</a> algorithm and requires less memory than an exhaustive COUNT DISTINCT operation. Having a smaller memory footprint will the function less likely to spill memory to disk compared to a precise COUNT DISTINCT operation.</p>
<p>Let us try in on AdwentureWorksLT sample database running on Azure SQL:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT 
	COUNT(DISTINCT [ProductID]) AS [Distinct_ProductIDs],
	APPROX_COUNT_DISTINCT([ProductID]) AS [Approx_Distinct_ProductIDs]
FROM [SalesLT].[SalesOrderDetail]
GO

SELECT 
	[ProductID], 
	COUNT(DISTINCT [LineTotal]) AS [Distinct_Line_Total_Per_ProductID], 
	APPROX_COUNT_DISTINCT([rowguid]) AS [Distinc_LineTotal_Per_ProductID]
FROM [SalesLT].[SalesOrderDetail]
GROUP BY [ProductID]
ORDER BY [ProductID]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-3352" src="https://sqlpowered.com/wp-content/uploads/2019/10/APPROX_COUNT_DISTINCT_01.png" alt="" width="331" height="41" srcset="https://sqlpowered.com/wp-content/uploads/2019/10/APPROX_COUNT_DISTINCT_01.png 331w, https://sqlpowered.com/wp-content/uploads/2019/10/APPROX_COUNT_DISTINCT_01-150x19.png 150w, https://sqlpowered.com/wp-content/uploads/2019/10/APPROX_COUNT_DISTINCT_01-300x37.png 300w, https://sqlpowered.com/wp-content/uploads/2019/10/APPROX_COUNT_DISTINCT_01-160x20.png 160w, https://sqlpowered.com/wp-content/uploads/2019/10/APPROX_COUNT_DISTINCT_01-320x40.png 320w" sizes="auto, (max-width: 331px) 100vw, 331px" /></p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-3353" src="https://sqlpowered.com/wp-content/uploads/2019/10/APPROX_COUNT_DISTINCT_02.png" alt="" width="516" height="241" /></p>
<p>The result is quite interesting for anyone who will expect that for smaller data sets APPROX_COUNT_DISTINCT will return the same result as COUNT DISTINCT. Not exactly &#8211; significant differences are theRE, i.e. row 6 for Product_ID = 715 &#8211; there is double value to be approximated. So there is really no reason to not use COUNT DISTINCT for smaller data set where the overhead is minimal.  APPROX_COUNT_DISTINCT will make a great job on a really large data set where we need to do raw estimates of rows count and running the precise COUNT DISTINCT will consume a huge amount of system resources.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/approx_count_distinct/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Removing decimal places from a number without rounding</title>
		<link>https://sqlpowered.com/removing-decimal-places-from-number-without-rounding/</link>
					<comments>https://sqlpowered.com/removing-decimal-places-from-number-without-rounding/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Wed, 11 Sep 2019 21:24:44 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=3188</guid>

					<description><![CDATA[ROUND() is a well-known function in SQL Server. Most of us know only that two parameters can be used like ROUND(99,95, 2). This will do standard mathematical up/down rounding of numbers in the first parameter for the number of decimal places from the second parameter. But there is also an...]]></description>
										<content:encoded><![CDATA[<p><a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/round-transact-sql?view=sql-server-2017" target="_blank" rel="noopener noreferrer">ROUND()</a> is a well-known function in SQL Server. Most of us know only that two parameters can be used like ROUND(99,95, 2). This will do standard mathematical up/down rounding of numbers in the first parameter for the number of decimal places from the second parameter.</p>
<p>But there is also an option to use a <strong>third parameter</strong> called <em>function</em> specified in BOL as:</p>
<ul>
<li>Function is the type of operation to perform.</li>
<li>Function must be tinyint, smallint, or int.</li>
<li>When function is omitted or has a value of 0 (default), numeric_expression is rounded.</li>
<li>When a value other than 0 is specified, numeric_expression is truncated.</li>
</ul>
<p>Let&#8217;s observe this simple example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT 'ROUND down', ROUND(5.1, 0) UNION ALL
SELECT 'ROUND up', ROUND(5.9, 0) UNION ALL
SELECT 'TRIM only', ROUND(5.1, 0, 1) UNION ALL
SELECT 'TRIM only', ROUND(5.9, 0, 1)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-3191" src="https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Trim.png" alt="" width="235" height="77" srcset="https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Trim.png 235w, https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Trim-150x49.png 150w, https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Trim-160x52.png 160w" sizes="auto, (max-width: 235px) 100vw, 235px" /></p>
<p>Using the third parameter with a different value than 0 we have <strong>simply trimmed decimal places</strong> which can be really handy in case of some specific need for reporting when there is a requirement to report numbers without decimal place but also have a proper value at the total row.</p>
<p>Let me mention one important thing we should remember using the ROUND()  function.</p>
<p>Consider the following example:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT ROUND(9.9, 0)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-3190" src="https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Numeric_Error.png" alt="" width="518" height="33" srcset="https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Numeric_Error.png 518w, https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Numeric_Error-150x10.png 150w, https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Numeric_Error-300x19.png 300w, https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Numeric_Error-160x10.png 160w, https://sqlpowered.com/wp-content/uploads/2019/10/ROUND_Numeric_Error-320x20.png 320w" sizes="auto, (max-width: 518px) 100vw, 518px" /></p>
<p>Are you surprised about this error?</p>
<p>The explanation is easy: value 9.9 is handled in this case as to be DECIMAL(2,1). Rounding it to 0 decimal places means that the new value will be 10 and this doesn&#8217;t fit into the original DECIMAL(2,1) data type.</p>
<p>This can be easily fixed like this:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT ROUND(CAST(9.9 AS DECIMAL(3,1)), 0)
GO</pre>
<p>I saw a lot of production disasters caused by this simple piece of code during my career.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/removing-decimal-places-from-number-without-rounding/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>HASHBYTES(&#8216;SHA2_256&#8217;, ?) generates two different values for the same string! Not really:)</title>
		<link>https://sqlpowered.com/hashbytes_sha2_256-generates-two-different-values-for-the-same-string-not-really/</link>
					<comments>https://sqlpowered.com/hashbytes_sha2_256-generates-two-different-values-for-the-same-string-not-really/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Fri, 08 Mar 2019 22:04:00 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=2924</guid>

					<description><![CDATA[One friend called me yesterday that he can&#8217;t believe what&#8217;s happening to him: he is saving various strings to the table and to check if the string already exists he is generating hashes using the SHA2_256 algorithm. But today he has seen that for the same string stored in two...]]></description>
										<content:encoded><![CDATA[<p>One friend called me yesterday that he can&#8217;t believe what&#8217;s happening to him: he is saving various strings to the table and to check if the string already exists he is generating hashes using the SHA2_256 algorithm. But today he has seen that for the same string stored in two different rows SHA2_256 is giving him different hash values. He is thinking there must be some &#8220;magic&#8221; around this particular string.</p>
<p>A simple demonstration of the situation:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">DECLARE @String1 NVARCHAR(200) 
DECLARE @String2 NVARCHAR(200) 

SET @String1 = '&lt;tsql_stack&gt;&lt;frame database_name = ''Custom_PL''/&gt;&lt;/tsql_stack&gt;'
SET @String2 = '&lt;tsql_stack&gt;&lt;frame database_name = ''Custom_Pl''/&gt;&lt;/tsql_stack&gt;'

SELECT @String1 AS StringValue
UNION
SELECT @String2

SELECT HASHBYTES('SHA2_256', @String1) HashValue
UNION
SELECT HASHBYTES('SHA2_256', @String2)
GO</pre>
<p>We have declared two string variables and set the value of both to the &#8220;magical&#8221; string. Then we are comparing these two strings using the UNION operator and the result is as expected: only one row is returned. But when we do the same with hashes we can see two different values instead of a single one like with the previous UNION:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2944" src="https://sqlpowered.com/wp-content/uploads/2019/03/Screenshot-08.03.2019-22_51_05.png" alt="" width="479" height="130" srcset="https://sqlpowered.com/wp-content/uploads/2019/03/Screenshot-08.03.2019-22_51_05.png 479w, https://sqlpowered.com/wp-content/uploads/2019/03/Screenshot-08.03.2019-22_51_05-150x41.png 150w, https://sqlpowered.com/wp-content/uploads/2019/03/Screenshot-08.03.2019-22_51_05-300x81.png 300w, https://sqlpowered.com/wp-content/uploads/2019/03/Screenshot-08.03.2019-22_51_05-160x43.png 160w, https://sqlpowered.com/wp-content/uploads/2019/03/Screenshot-08.03.2019-22_51_05-320x87.png 320w" sizes="auto, (max-width: 479px) 100vw, 479px" /></p>
<p>What&#8217;s going wrong?</p>
<p>Oki. Let&#8217;s stop joking. I will give you small help:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="sql">SELECT CONVERT (varchar, DATABASEPROPERTYEX(DB_NAME(),'collation')) Collation</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2945" src="https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_CollationTrick.png" alt="" width="277" height="45" srcset="https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_CollationTrick.png 277w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_CollationTrick-150x24.png 150w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_CollationTrick-160x26.png 160w" sizes="auto, (max-width: 277px) 100vw, 277px" /></p>
<p>Any idea? I have one: don&#8217;t trust what you see: double-check our strings:</p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2947" src="https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1.png" alt="" width="806" height="46" srcset="https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1.png 806w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1-150x9.png 150w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1-300x17.png 300w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1-768x44.png 768w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1-160x9.png 160w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1-320x18.png 320w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1-520x30.png 520w, https://sqlpowered.com/wp-content/uploads/2019/03/SHA2_256_DifferentValues_Explanation-1-720x41.png 720w" sizes="auto, (max-width: 806px) 100vw, 806px" /></p>
<p>Do you see it? There is the same letter &#8220;L&#8221; one time as capital and other times the lower case.</p>
<p>If you will check the collation then it&#8217;s obvious: CI = case insensitive which means that the UNION statement will compare these two strings as equal. Bit this isn&#8217;t true for the SHA2_256 algorithm which is a binary function knowing zero about case sensitivity.</p>
<p>Don&#8217;t trust what you see:)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/hashbytes_sha2_256-generates-two-different-values-for-the-same-string-not-really/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>STRING_AGG() pro konečně smysluplně řeší spojování řetězců v datových setech</title>
		<link>https://sqlpowered.com/string_agg/</link>
					<comments>https://sqlpowered.com/string_agg/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sat, 05 Jan 2019 21:41:43 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=2836</guid>

					<description><![CDATA[Funkce STRING_AGG(), novinka v SQL Serveru 2017, řeší nekonečné problémy s tím, jak spojit dohromady řetězce z více řádků v rámci jednoho datového setu. V průběhu let jsme pracovali nejčastěji s využitím FOR XML PATH (nebo JSON), případně s deklarací proměnné a sčítáním řetězců. To vše už nyní budeme používat...]]></description>
										<content:encoded><![CDATA[<p>Funkce <a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-2017" target="_blank" rel="noopener noreferrer">STRING_AGG()</a>, novinka v SQL Serveru 2017, řeší nekonečné problémy s tím, jak spojit dohromady řetězce z více řádků v rámci jednoho datového setu. V průběhu let jsme pracovali nejčastěji s využitím <a href="https://sqlpowered.com/spojeni-retezcu-pomoci-for-xml-path/">FOR XML PATH</a> (nebo JSON), případně s deklarací proměnné a sčítáním řetězců. To vše už nyní budeme používat zřejmě jen tehdy, vyžádá-li si to zpětná kompatibilita.</p>
<p>Pojďme si ukázat, jak STRING_AGG() funguje v praxi.K tomu si nejprve vytvoříme jednoduchá testovací data: objednávky a jejich položky:</p>
<pre class="lang:tsql decode:true ">DROP TABLE [dbo].[OrderItems]
DROP TABLE [dbo].[Orders]
GO

-- create sample tables
CREATE TABLE dbo.Orders
(
    Id INT IDENTITY(1,1) PRIMARY KEY,
    OrderDate DATETIME NOT NULL
)
GO

CREATE TABLE dbo.OrderItems 
(
    Id INT IDENTITY(1,1) PRIMARY KEY,
    OrderId INT NOT NULL REFERENCES dbo.Orders,
	ProductName VARCHAR(100) NOT NULL,
    Amount INT NOT NULL,
    Price INT NOT NULL,
    Note VARCHAR(50)
)
GO

-- populate tables with data
INSERT dbo.Orders VALUES ('2018-01-01')
INSERT dbo.Orders VALUES ('2018-02-02')
INSERT dbo.Orders VALUES ('2018-03-03')
INSERT dbo.Orders VALUES ('2018-03-04')
GO

INSERT dbo.[OrderItems]
	( [OrderId], [ProductName], [Amount], [Price], [Note] )
    SELECT Id, 'ProductA', 10, 1500, 'NoteOrderItem1' FROM dbo.Orders WHERE [Id] = 1 UNION ALL
    SELECT Id, 'ProductB', 5, 750, 'NoteOrderItem2' FROM dbo.Orders WHERE [Id] = 1 UNION ALL
	SELECT Id, 'ProductC', 3, 500, 'NoteOrderItem3' FROM dbo.Orders WHERE [Id] = 1 UNION ALL
	SELECT Id, 'ProductA', 15, 300, 'NoteOrderItem1' FROM dbo.Orders WHERE [Id] = 2 UNION ALL
	SELECT Id, 'ProductX', 8, 200, 'NoteOrderItem2' FROM dbo.Orders WHERE [Id] = 2 UNION ALL
	SELECT Id, 'ProductF', 15, 300, 'NoteOrderItem1' FROM dbo.Orders WHERE [Id] = 3 UNION ALL
	SELECT Id, 'ProductG', 8, 200, 'NoteOrderItem2' FROM dbo.Orders WHERE [Id] = 3
GO

-- review test data
SELECT * FROM [dbo].[Orders] [o]
SELECT * FROM [dbo].[OrderItems] [oi]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2839" src="https://sqlpowered.com/wp-content/uploads/2019/01/String_Agg_1.png" alt="" width="253" height="111" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/String_Agg_1.png 253w, https://sqlpowered.com/wp-content/uploads/2019/01/String_Agg_1-150x66.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/String_Agg_1-160x70.png 160w" sizes="auto, (max-width: 253px) 100vw, 253px" /></p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2840" src="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_2.png" alt="" width="474" height="177" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_2.png 474w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_2-150x56.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_2-300x112.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_2-160x60.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_2-320x119.png 320w" sizes="auto, (max-width: 474px) 100vw, 474px" /></p>
<p>Na daty si postupně vyzkoušíme různé použití STRING_AGG() funkce a to tak, že budeme agregovat hodnoty sloupce ProductName pro jednotlivé objednávky a názvy produktů od sebe oddělíme čárkou:</p>
<pre class="lang:tsql mark:2 decode:true ">SELECT o.[Id], o.[OrderDate], 
       STRING_AGG(oi.[ProductName], ', ') Products
FROM dbo.[Orders] [o]
	LEFT JOIN [dbo].[OrderItems] [oi] ON [oi].[OrderId] = [o].[Id]
GROUP BY o.[Id], o.[OrderDate]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2844" src="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_1.png" alt="" width="460" height="111" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_1.png 460w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_1-150x36.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_1-300x72.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_1-160x39.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_1-320x77.png 320w" sizes="auto, (max-width: 460px) 100vw, 460px" /></p>
<p>Toto je nejjednodušší možné použití funkce STRING_AGG(): prostá agregace hodnot sloupce ProductName za sebou, jednotlivé položky odděleny čárkou. Všimněte si jedné opravu zásadní věci: STRING_AGG() nepřidává separátor za poslední položku v seznamu, což je naprosto úžasné, neboť jinak bychom to v 99% případů ještě obalovali dalším zbytečným kódem, abychom odstranili čásku za poslední položkou.</p>
<p>V rámci funkce STRING_AGG() můžeme používat i různé expressions a se slučovanými řetězci dále libovolně pracovat. V následujícím příkladu např. pomocí ISNULL() šetříme chybějící produkty pro případ, že objednávky nemá žádné položky:</p>
<pre class="lang:tsql mark:2 decode:true ">SELECT o.[Id], o.[OrderDate], 
       STRING_AGG(ISNULL(oi.[ProductName], '0 order items'), ', ') Products
FROM dbo.[Orders] [o]
	LEFT JOIN [dbo].[OrderItems] [oi] ON [oi].[OrderId] = [o].[Id]
GROUP BY o.[Id], o.[OrderDate]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2843" src="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_2.png" alt="" width="460" height="111" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_2.png 460w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_2-150x36.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_2-300x72.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_2-160x39.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_2-320x77.png 320w" sizes="auto, (max-width: 460px) 100vw, 460px" /></p>
<p>Funkci STRING_AGG() můžeme použít i s přídavkem WITH GROUP(), čímž získáme možnost určit pořadí, v jakém budou řetězce spojovány:</p>
<pre class="lang:tsql mark:3 decode:true ">SELECT o.[Id], o.[OrderDate], 
       STRING_AGG(ISNULL(oi.[ProductName], '0 order items'), ', ')
           WITHIN GROUP (ORDER BY oi.ProductName DESC) AS Products
FROM dbo.[Orders] [o]
	LEFT JOIN [dbo].[OrderItems] [oi] ON [oi].[OrderId] = [o].[Id]
GROUP BY o.[Id], o.[OrderDate]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2845" src="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_3.png" alt="" width="460" height="111" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_3.png 460w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_3-150x36.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_3-300x72.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_3-160x39.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/String_AGG_Result_3-320x77.png 320w" sizes="auto, (max-width: 460px) 100vw, 460px" /></p>
<p>Nyní jsou názvy produktů seřazeny podle abecedy obráceně. Pro řazení můžeme používat libovolné dostupné sloupce v rámci dotazu, tedy klidně řadit podle hodnot z jiných tabulek, než ve které je náš agregovaný řetězec.</p>
<p>Myslím, že STRING_AGG() je opravdu podařená funkce a podle mě se stane vůbec nejpoužívanější novinkou v SQL Serveru 2017.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/string_agg/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TRIM() přichází: LTRIM(RTRIM()) v propadlišti dějin</title>
		<link>https://sqlpowered.com/trim-string-function/</link>
					<comments>https://sqlpowered.com/trim-string-function/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sat, 05 Jan 2019 20:07:51 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=2832</guid>

					<description><![CDATA[Nová funkce TRIM(), která přichází v SQL Serveru 2017, je opravu jen logickou kombinací dvou funkcí RTRIM() a LTRIM() vnořených do sebe, ale i tak se jedná o milé vylepšení T-SQL jazyka, který se tím kompatibilitou zase o kousek blíží SQL standardům implementovaných v konkurenčních RDBMS. Syntaktické a funkční srovnání...]]></description>
										<content:encoded><![CDATA[<p>Nová funkce TRIM(), která přichází v SQL Serveru 2017, je opravu jen logickou kombinací dvou funkcí RTRIM() a LTRIM() vnořených do sebe, ale i tak se jedná o milé vylepšení T-SQL jazyka, který se tím kompatibilitou zase o kousek blíží SQL standardům implementovaných v konkurenčních RDBMS.</p>
<p>Syntaktické a funkční srovnání všech funkcí ukazuje následující kód:</p>
<pre class="lang:tsql mark:5 decode:true">SELECT ' AAA '
UNION ALL
SELECT LTRIM(RTRIM(' AAA '))
UNION ALL
SELECT TRIM(' AAA ')
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2833" src="https://sqlpowered.com/wp-content/uploads/2019/01/Trim_String_Function.png" alt="" width="178" height="67" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/Trim_String_Function.png 178w, https://sqlpowered.com/wp-content/uploads/2019/01/Trim_String_Function-150x56.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/Trim_String_Function-160x60.png 160w" sizes="auto, (max-width: 178px) 100vw, 178px" /></p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/trim-string-function/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>TRANSLATE() jako alternativa k řetězení REPLACE() funkcí</title>
		<link>https://sqlpowered.com/translate-retezcova-funkce/</link>
					<comments>https://sqlpowered.com/translate-retezcova-funkce/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sat, 05 Jan 2019 19:29:44 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=2823</guid>

					<description><![CDATA[Další novou zajímavou funkcí pro práci s řetězci v SQL Serveru 2017 je funkce TRANSLATE(), která funguje jako šikovná náhrada více REPLACE() funkcí vnořených do sebe. Funkce má tři vstupní parametry: TRANSLATE ( inputString, characters, translations) inputString je řetězec, v němž chceme provést nahrazení characters jsou znaky, které chceme nahradit...]]></description>
										<content:encoded><![CDATA[<p>Další novou zajímavou funkcí pro práci s řetězci v SQL Serveru 2017 je funkce <a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/translate-transact-sql?view=sql-server-2017" target="_blank" rel="noopener noreferrer">TRANSLATE()</a>, která funguje jako šikovná náhrada více REPLACE() funkcí vnořených do sebe. Funkce má tři vstupní parametry:</p>
<pre class=""><code class="">TRANSLATE ( inputString, characters, translations) </code></pre>
<ul>
<li><em>inputString</em> je řetězec, v němž chceme provést nahrazení</li>
<li><em>characters</em> jsou znaky, které chceme nahradit</li>
<li><em>translactions</em> jsou znaky, které chceme nově vložit</li>
</ul>
<p>Ukázkový příklad pak vypadá takto:</p>
<pre class="lang:tsql decode:true ">SELECT 'TRANSLATE(''[Hi]'', ''[]'', ''()'')' FceCall, TRANSLATE('[Hi]', '[]', '()') Result
UNION ALL
SELECT 'TRANSLATE(''[Hi sir]'', ''[sir]'', ''(man)'')', TRANSLATE('[Hi sir]', '[sir]', '(man)')
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2825" src="https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-20_25_57.png" alt="" width="365" height="67" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-20_25_57.png 365w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-20_25_57-150x28.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-20_25_57-300x55.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-20_25_57-160x29.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-20_25_57-320x59.png 320w" sizes="auto, (max-width: 365px) 100vw, 365px" /></p>
<p>Na prvním řádku vidíme jednoduché nahrazení dvou různých znaků dvěma novými znaky.</p>
<p>Druhý řádek nám ilustruje, jak se chová celá funkce ještě názorněji: nahrazuje se tu znak za znak, takže jsme sice <em>jakoby</em> nahradili slovo &#8220;sir&#8221; slovem &#8220;man&#8221;, ovšem jak vidíme na výstupním řetězci, ve skutečnosti jsme řekli, že chceme každé písmeno &#8220;i&#8221; nahradit písmenem &#8220;a&#8221;.</p>
<p>Pokud bychom chtěli řádek 1 zapsat postaru pomocí řetězení REPLACE() funkcí, kód by vypadal takto:</p>
<pre class="lang:tsql decode:true ">SELECT REPLACE(REPLACE('[Hi]', '[', '('), ']', ')')</pre>
<p>Důležité pravidlo, které musíme dodržet je, že hodnoty parametrů <em>characters</em> a <em>translactions</em> musí mít stejnou délku, jinými slovy, musíme mít vždy dvoji starých/nových znaků k nahrazení:</p>
<pre class="lang:tsql decode:true ">SELECT TRANSLATE('abc', 'ab', 'c')</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2829" src="https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error.png" alt="" width="775" height="34" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error.png 775w, https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error-150x7.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error-300x13.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error-768x34.png 768w, https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error-160x7.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error-320x14.png 320w, https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error-520x23.png 520w, https://sqlpowered.com/wp-content/uploads/2019/01/TranslateStringFunction_error-720x32.png 720w" sizes="auto, (max-width: 775px) 100vw, 775px" /></p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/translate-retezcova-funkce/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CONCAT_WS() &#8211; Nová funkce pro spojení řetězců s výběrem separátoru</title>
		<link>https://sqlpowered.com/concat_ws/</link>
					<comments>https://sqlpowered.com/concat_ws/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Sat, 05 Jan 2019 17:25:21 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=2815</guid>

					<description><![CDATA[Od SQL Serveru 2012 máme možnost spojovat řetězce pomocí funkce CONCAT(), která však neumí nic jiného, než prosté spojení řetězců za sebe a není možné specifikovat separátor, kterým bychom od sebe jednotlivé řetězce mohli oddělit. SQL Server 2017 proto přichází s novou funkcí CONCAT_WS(), kde již přídavek WS napovídá, že...]]></description>
										<content:encoded><![CDATA[<p>Od SQL Serveru 2012 máme možnost spojovat řetězce pomocí funkce CONCAT(), která však neumí nic jiného, než prosté spojení řetězců za sebe a není možné specifikovat separátor, kterým bychom od sebe jednotlivé řetězce mohli oddělit. SQL Server 2017 proto přichází s novou funkcí <a href="https://docs.microsoft.com/en-us/sql/t-sql/functions/concat-ws-transact-sql?view=sql-server-2017" target="_blank" rel="noopener noreferrer">CONCAT_WS()</a>, kde již přídavek WS napovídá, že se jedná o zkratku z anglického With Separator.</p>
<p>Porovnejme si nyní obě funkce na jednoduchém příkladu:</p>
<pre class="lang:tsql mark:5,7 decode:true ">DECLARE @String1 NVARCHAR(100) = 'String1'
DECLARE @String2 NVARCHAR(100) = 'String2'
DECLARE @String3 NVARCHAR(100) = 'String3'

SELECT 'CONCAT()' [Function],	 CONCAT(@String1, @String2, @String3) Result
UNION ALL
SELECT 'CONCAT()_WS' [Function], CONCAT_WS(', ', @String1, @String2, @String3)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2818" src="https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_20_00.png" alt="" width="328" height="67" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_20_00.png 328w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_20_00-150x31.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_20_00-300x61.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_20_00-160x33.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_20_00-320x65.png 320w" sizes="auto, (max-width: 328px) 100vw, 328px" /></p>
<p>Dobrá zpráva je, že separátor můžeme zaslat do funkce i jako parametr, čímž získáváme mnohem větší svobodu při psaní kódu:</p>
<pre class="lang:tsql decode:true ">DECLARE @String1 NVARCHAR(100) = 'String1'
DECLARE @String2 NVARCHAR(100) = 'String2'
DECLARE @String3 NVARCHAR(100) = 'String3'

DECLARE @Separator CHAR(1) = '-'

SELECT 'CONCAT()_WS' [Function], CONCAT_WS(@Separator, @String1, @String2, @String3)
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2819" src="https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_24_37.png" alt="" width="322" height="45" srcset="https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_24_37.png 322w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_24_37-150x21.png 150w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_24_37-300x42.png 300w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_24_37-160x22.png 160w, https://sqlpowered.com/wp-content/uploads/2019/01/Screenshot-05.01.2019-18_24_37-320x45.png 320w" sizes="auto, (max-width: 322px) 100vw, 322px" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/concat_ws/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Executing Scalar Functions</title>
		<link>https://sqlpowered.com/executing-scalar-functions/</link>
					<comments>https://sqlpowered.com/executing-scalar-functions/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Wed, 18 May 2016 19:23:50 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=1873</guid>

					<description><![CDATA[There are several ways how to execute scalar functions. A lot of them are well known: using SELECT or SET. But did you know that you can use EXECUTE too? We will play with all the options in this article and especially with EXECUTE we will enjoy it:) First, create...]]></description>
										<content:encoded><![CDATA[<p>There are several ways how to execute scalar functions. A lot of them are well known: using SELECT or SET. But did you know that you can use EXECUTE too? We will play with all the options in this article and especially with EXECUTE we will enjoy it:)<span id="more-1873"></span></p>
<p>First, create a simple scalar function to play with:</p>
<pre class="lang:tsql decode:true">CREATE FUNCTION dbo.f_MergeStrings(
	@String1 VARCHAR(100),
	@String2 VARCHAR(100)
)
RETURNS VARCHAR(200)
AS
BEGIN
	RETURN @String1 + @String2
END
GO</pre>
<p>There is no magic: two input strings are concatenated to one.</p>
<h3>1. SELECT</h3>
<pre class="lang:tsql decode:true">SELECT dbo.f_MergeStrings('AB', 'CD')
GO</pre>
<p>I will say this is the most common way how we are calling scalar functions to get the result. For sure there can be a complex SELECT statement and a scalar function can be called anywhere inside it where expressions are allowed (in place of columns in SELECT, WHERE, joins, etc.)</p>
<p>For sure we can assign a scalar function return value to another variable:</p>
<pre class="lang:tsql mark:3 decode:true">DECLARE @FinalString VARCHAR(200)

SELECT @FinalString = dbo.f_MergeStrings('AB', 'CD')

PRINT @FinalString
GO</pre>
<h3>2. SET</h3>
<p>SET works very similar to SELECT:</p>
<pre class="lang:tsql mark:3 decode:true">DECLARE @FinalString VARCHAR(200)

SET @FinalString = dbo.f_MergeStrings('AB', 'CD')

PRINT @FinalString
GO</pre>
<p>There is one exception: it can´t be called without assigning value to a variable like (syntax error)</p>
<pre class="lang:tsql decode:true">SET dbo.f_MergeStrings('AB', 'CD')
GO</pre>
<h3>3. EXECUTE</h3>
<p>Yes, you can call the scalar function using <a href="https://msdn.microsoft.com/en-us/library/ms188332.aspx">EXECUTE</a> without all the parentheses as you do it for stored procedures:</p>
<pre class="lang:tsql mark:3 decode:true">DECLARE @FinalString VARCHAR(200)

EXEC @FinalString = dbo.f_MergeStrings 'AB', 'CD'

PRINT @FinalString
GO</pre>
<p>You can also use long-form with full parameter names:</p>
<pre class="lang:tsql mark:3 decode:true">DECLARE @FinalString VARCHAR(200)

EXEC @FinalString = dbo.f_MergeStrings @String1 = 'AB', @String2 = 'CD'

PRINT @FinalString
GO</pre>
<p>It´s really funny that you can execute a scalar function the way that nothing is returned to the client &#8211; the result is completely lost:</p>
<pre class="lang:tsql decode:true">EXEC dbo.f_MergeStrings @String1 = 'AB', @String2 = 'CD'
GO</pre>
<p>You can use a lot of the clauses supported by EXECUTE:</p>
<pre class="lang:tsql decode:true ">DECLARE @FinalString VARCHAR(200)

EXEC @FinalString = dbo.f_MergeStrings 'AB', 'CD' WITH RECOMPILE

EXEC @FinalString = dbo.f_MergeStrings 'AB', 'CD' WITH RESULT SETS UNDEFINED

EXEC @FinalString = dbo.f_MergeStrings 'AB', 'CD' WITH RESULT SETS NONE
GO
</pre>
<p>Except RECOMPILE they don´t have any effect because there is no result set to be returned.</p>
<p>If you will try set an explicit result set the statement will fail and the error message is clear:</p>
<pre class="lang:tsql decode:true">DECLARE @FinalString VARCHAR(200)

EXEC @FinalString = dbo.f_MergeStrings 'AB', 'CD' WITH RESULT SETS (([String] NVARCHAR(20)))
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1878" src="https://sqlpowered.com/wp-content/uploads/2016/05/Execute-Scalar-Functions-With-Result-Sets.png" alt="Execute-Scalar-Functions-With-Result-Sets" width="1158" height="41" /></p>
<p>Using dynamic SQL you can run the code under different security context:</p>
<pre class="lang:tsql decode:true ">EXEC ('DECLARE @FinalString VARCHAR(200); 
	   EXEC @FinalString = dbo.f_MergeStrings ''AB'', ''CD''; 
	   PRINT @FinalString') AS LOGIN = 'SQLpowered'
GO</pre>
<p>And If you want you can wrap it to sp_executesql:</p>
<pre class="lang:tsql decode:true">DECLARE @String1 VARCHAR(100)
DECLARE @String2 VARCHAR(100)
DECLARE @FinalString VARCHAR(200)
DECLARE @Params NVARCHAR(500)

SET @String1 = 'AB'
SET @string2 = 'CD'

SET @Params = N'@String1 VARCHAR(200), @String2 VARCHAR(200), @FinalString VARCHAR(200) OUTPUT'

EXECUTE sp_executesql N'EXEC @FinalString = dbo.f_MergeStrings @String1, @String2', @Params, 
						@String1 = @String1, @String2 = @String2, @FinalString = @FinalString OUTPUT

PRINT @FinalString
GO</pre>
<p>Which method is the best? I will say the SET and SELECT are something we are familiar with. EXECUTE is most of the time used for calling stored procedures or dynamic SQL and it can be a big surprise for people to see it used with scalar functions.</p>
<p>Further reading:</p>
<ul>
<li><a href="https://www.mssqltips.com/sqlservertip/1888/when-to-use-set-vs-select-when-assigning-values-to-variables-in-sql-server">When to use SET vs SELECT when assigning values to variables in SQL Server</a> (<a href="https://www.mssqltips.com/">mssqltips.com</a>)</li>
<li><a href="http://vyaskn.tripod.com/differences_between_set_and_select.htm">http://vyaskn.tripod.com/differences_between_set_and_select.htm</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/executing-scalar-functions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Modifying data using table valued functions</title>
		<link>https://sqlpowered.com/modifying-data-using-table-valued-functions/</link>
					<comments>https://sqlpowered.com/modifying-data-using-table-valued-functions/#respond</comments>
		
		<dc:creator><![CDATA[Jan Dvořák]]></dc:creator>
		<pubDate>Wed, 13 Apr 2016 21:33:09 +0000</pubDate>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[functions]]></category>
		<guid isPermaLink="false">https://sqlpowered.com/?p=1411</guid>

					<description><![CDATA[Is it possible to modify data in T-SQL using inline table valued functions? It´s surprising, but YES, it´s possible. If we will remember the sentence from BOL, that we can think about inline table valued functions as  they are like parameterized views, then it&#8217;s more clear that we can modify...]]></description>
										<content:encoded><![CDATA[<p>Is it possible to modify data in T-SQL using inline table valued functions? It´s surprising, but YES, it´s possible. If we will remember the sentence from BOL, that we can think about inline table valued functions as  they are like parameterized views, then it&#8217;s more clear that we can modify data using them like we can do it using views. Let us show how it works.<span id="more-1411"></span></p>
<p>First we will create dbo.SampleTable with simple data inside:</p>
<pre class="lang:tsql decode:true">CREATE TABLE [dbo].[SampleTable] 
(
 [ID] INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
 [Value] NVARCHAR(100)
)
GO

INSERT INTO [dbo].[SampleTable]
 VALUES ('A'), ('B'), ('C'), ('D')
GO

SELECT * FROM [dbo].[SampleTable]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1412" src="https://sqlpowered.com/wp-content/uploads/2016/04/Modifying-data-with-table-valued-function-1.png" alt="Modifying-data-with-table-valued-function-1" width="100" height="96" /></p>
<p>As next create simple inline table valued function to return all data from dbo.SampleTable:</p>
<pre class="lang:tsql decode:true">CREATE FUNCTION [dbo].[ft_ChangeValue]()
RETURNS TABLE
AS
RETURN 
(
	SELECT [ID], [Value]
	FROM [dbo].[SampleTable]
)
GO</pre>
<p>We will test DML operations firing them against our function now:</p>
<p>INSERT:</p>
<pre class="lang:tsql decode:true">SET IDENTITY_INSERT [dbo].[SampleTable] ON

INSERT INTO [dbo].[ft_ChangeValue]() (ID, VALUE)
	VALUES (5, 'E from function')

SET IDENTITY_INSERT [dbo].[SampleTable] OFF
GO

SELECT * FROM [dbo].[SampleTable]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1413" src="https://sqlpowered.com/wp-content/uploads/2016/04/Modifying-data-with-table-valued-function-2.png" alt="Modifying-data-with-table-valued-function-2" width="145" height="115" /></p>
<p>UPDATE:</p>
<pre class="lang:tsql decode:true">UPDATE [chv]
	SET [chv].[Value] = 'C updated'
FROM [dbo].[ft_ChangeValue]() [chv]
WHERE [ID] = 3
GO

SELECT * FROM [dbo].[SampleTable]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1414" src="https://sqlpowered.com/wp-content/uploads/2016/04/Modifying-data-with-table-valued-function-3.png" alt="Modifying-data-with-table-valued-function-3" width="145" height="115" /></p>
<p>DELETE:</p>
<pre class="lang:tsql decode:true">DELETE FROM [dbo].[ft_ChangeValue]()
WHERE [ID] = 2
GO

SELECT * FROM [dbo].[SampleTable]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1415" src="https://sqlpowered.com/wp-content/uploads/2016/04/Modifying-data-with-table-valued-function-4.png" alt="Modifying-data-with-table-valued-function-4" width="145" height="96" /></p>
<p>One question can be obvious: How this works with parameters? Pretty well.</p>
<p>We will modify our function to include @ID as a parameter and filter dbo.SampleRows by this value:</p>
<pre class="lang:tsql decode:true">CREATE FUNCTION [dbo].[ft_ChangeValue](
	@ID INT
)
RETURNS TABLE
AS
RETURN 
(
	SELECT [ID], [Value]
	FROM [dbo].[SampleTable]
	WHERE ID = @ID
)
GO</pre>
<p>And DML operations:</p>
<p>INSERT:</p>
<pre class="lang:tsql decode:true ">SET IDENTITY_INSERT [dbo].[SampleTable] ON

INSERT INTO [dbo].[ft_ChangeValue](NULL) (ID, VALUE)
	VALUES (5, 'E from function with parameter')

SET IDENTITY_INSERT [dbo].[SampleTable] OFF
GO

SELECT * FROM [dbo].[SampleTable]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1421" src="https://sqlpowered.com/wp-content/uploads/2016/04/Modifying-data-with-table-valued-function-5.png" alt="Modifying-data-with-table-valued-function-5" width="217" height="115" /></p>
<p>Instead of the NULL parameter value we can use any value but it has no effect on INSERT operation. With UPDATE and DELETE operation there is more fun and @ID value is really useful:</p>
<p>UPDATE:</p>
<pre class="lang:tsql decode:true">UPDATE [chv]
	SET [chv].[Value] = 'C updated from function with parameter'
FROM [dbo].[ft_ChangeValue](3) [chv]
GO

SELECT * FROM [dbo].[SampleTable]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1422" src="https://sqlpowered.com/wp-content/uploads/2016/04/Modifying-data-with-table-valued-function-6.png" alt="Modifying-data-with-table-valued-function-6" width="259" height="115" /></p>
<p>DELETE:</p>
<pre class="lang:tsql decode:true ">DELETE FROM [dbo].[ft_ChangeValue](2)
GO

SELECT * FROM [dbo].[SampleTable]
GO</pre>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-1423" src="https://sqlpowered.com/wp-content/uploads/2016/04/Modifying-data-with-table-valued-function-7.png" alt="Modifying-data-with-table-valued-function-7" width="259" height="96" /></p>
<p>Conclusion: Yes, it works. BUT: For 99% of people it will be surprise to see this to be used. It is not intuitive enough and I will say slightly against the nature of the SQL standards. Plus we are limited there by lack of implementation of few features we can use with views like WITH CHECK OPTION.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://sqlpowered.com/modifying-data-using-table-valued-functions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
