Pivoting using Coalesce

Mikhail Firsov 1,881 Reputation points
2021-07-27T10:44:20.423+00:00

Hello!

Yesterday I got the following tip from mssqltips.com: The Many Uses of Coalesce in SQL Server and was puzzled a lot: I still don't understand what "feature" of Coalesce allows it to pivot data.

According to the MS's documentation coalesce just returns the first non-null value and that is all, but when used with the variable - coalesce (variable, '') + ... it may be used to pivot data:
118264-01.png

Here are the two examples showing that adding "coalesce" to the code changes nothing in the output...
118207-03.png
118208-02.png

...so why "coalesce (variable).. makes that variable to contain not only the last value (Executive) as in the second example but all of them instead???

SELECT @DepartmentName = COALESCE(@DepartmentName,'') + Name + ';'
FROM HumanResources.Department
WHERE (GroupName = 'Executive General and Administration')
SELECT @DepartmentName AS DepartmentNames
go

118292-05.png

Thank you in advance,
Michael

Developer technologies Transact-SQL
{count} votes

9 answers

Sort by: Most helpful
  1. Olaf Helper 47,436 Reputation points
    2021-07-27T12:21:14.88+00:00

    what "feature" of Coalesce allows it to pivot data.

    Has nothing directly to do with the COALESCE and you don't PIVOT data.
    The query you have is a "quirky update"; just search for


  2. Erland Sommarskog 121.4K Reputation points MVP Volunteer Moderator
    2021-07-27T12:43:59.693+00:00

    By the way, the connection between building a string aggregate and a dynamic pivot, is that a preparing step of a dynamic pivot is form a string with all the column values that will be the names of the columns in the dynamic pivot.

    0 comments No comments

  3. MelissaMa-MSFT 24,221 Reputation points
    2021-07-28T02:05:33.26+00:00

    Hi @Mikhail Firsov ,

    Adding to what other experts have said.

    I provide a simple example as below:

    create table #temp  
    (Groupid int,  
    Name varchar(10))  
      
    insert into #temp values  
    (1,'AA'),  
    (1,'BB'),  
    (1,NULL),  
    (1,'CC')  
      
    select * from #temp  
    

    118417-output.png

    As you could see, there is one NULL in the Name column.

    We would not get the expected output using below statement.

    DECLARE @Name VARCHAR(1000)   
      
    SELECT @Name = COALESCE(@Name,'') + Name + ';'    
    FROM #temp  
    WHERE Groupid=1  
      
    SELECT @Name AS Names   
    

    Output:

    Names  
    CC;  
    

    In this condition, we also need to add COALESCE to name column.

    DECLARE @Name VARCHAR(1000)   
      
    SELECT @Name = COALESCE(@Name,'') + COALESCE(Name,'') + ';'    
    FROM #temp  
    WHERE Groupid=1  
      
    SELECT @Name AS Names   
    

    Output:

    Names  
    AA;BB;;CC;  
    

    We could also use STRING_AGG instead even if there is NULL in the Name column.

    DECLARE @Name VARCHAR(1000)   
      
    SELECT @Name = STRING_AGG(Name ,';')    
    FROM #temp  
    WHERE Groupid=1  
      
    SELECT @Name AS Names   
    

    Best regards,
    Melissa


    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

  4. Ronen Ariely 15,206 Reputation points
    2021-07-29T03:25:13.127+00:00

    Good day,

    I hope this can help to clarify, so here are my 2 cents

    The Many Uses of Coalesce in SQL Server

    This post provide only a singe uses of COALESCE. It uses COALESCE in order to replace the value when is null and since it does not SET the value at the start then the COALESCE function replaces the first value into empty string ''

    Using Coalesce to Pivot

    As Olaf Helper said, This blog's post has nothing to do with PIVOT.

    It provides a solution to chain (concate/combine) values that are in a column in the table and add a separator between the values.

    Yes, string_agg NOW does the same thing as the command you posted.

    This is not correct

    First and the most important in this case is that the function string_agg do not add the separator when your value is NULL while the approach of using the COALESCE function simply replace the NULL with '' and adds the separator on NULL values

    DROP TABLE IF EXISTS #temp  
    create table #temp(Groupid int,Name varchar(10))  
    insert into #temp values  
    (1,'AA'),  
    (1,'BB'),  
    (1,NULL),  
    (1,'CC')  
    select * from #temp  
    GO  
    
    -- Using COALESCE  
    DECLARE @Name VARCHAR(1000)   
    SELECT @Name = COALESCE(@Name,'') + COALESCE(Name,'') + ';'    
    FROM #temp  
    SELECT @Name AS Names   
    GO -- AA;BB;;CC;  
    
    -- Using STRING_AGG  
    DECLARE @Name VARCHAR(1000)  
    SELECT @Name = STRING_AGG([Name],';')  
    FROM #temp  
    SELECT @Name AS Names   
    GO --AA;BB;CC;  
    

    Second different which is also VERY important but was not mention in the discussion yet is that the approach of using SELECT @X = @X + Column does not guarantees the order of the result and you might get different results while using the exact same database and query!

    In general, I HIGHLY recommend NOT to use this approach

    Using STRING_AGG we can configure the order using WITHIN GROUP ( ORDER BY <order_by_expression_list> [ ASC | DESC ] )

    In this condition, we also need to add COALESCE to name column.

    As I explained above, if there are values which are NULL then using COALESCE is not the same as STRING_AGG and the solution in old versions of SQL Server should be to use CASE statement if you want to use the approach ofSELECT @X = @X + Column`

    DECLARE @Name VARCHAR(1000)   
    SET @Name = ''  
    SELECT @Name = @Name + CASE WHEN [Name] IS NULL THEN '' ELSE [Name] + ';'  END  
    FROM #temp  
    SELECT @Name AS Names   
    GO --AA;BB;CC;  
    

    But again I do not like this approach and I will probably use FOR XML in this case for this task.

    Point to think about: if you have only a single value and you want to replace it when it is NULL then using COALESCE might work, but I would prefer to use the function which was built for this ISNULL

    Instead of using COALESCE to configure the starting value to '' I would prefer to use SET

    So instead of using :

    DECLARE @Name VARCHAR(1000)   
    SELECT @Name = COALESCE(@Name,'') + COALESCE(Name,'') + ';'    
    FROM #temp  
    SELECT @Name AS Names   
    GO -- AA;BB;;CC;  
    

    I would prefer probably using SET and ISNULL:

    DECLARE @Name VARCHAR(1000)   
    SET @Name = ''  
    SELECT @Name = @Name + ISNULL(Name,'') + ';'    
    FROM #temp  
    SELECT @Name AS Names   
    GO --AA;BB;;CC;  
    

    VERY IMPORTANT TO REMEMBER that using SET like in the last sample is NOT the same as using COALESCE if we have values which are NULL.

    Here is example and basic illustration of steps to explain the differences

    DECLARE @Name VARCHAR(1000)  
    SELECT @Name = COALESCE(@Name,'') + Name + ';'    
    FROM #temp  
    SELECT @Name AS Names   
    GO -- CC;  
    --Why?  
    -- Step 1: before we start the value is null so the server use '' and add AA = AA  
    -- Step 2: the server use 'AA' and add BB = AA;BB;  
    -- Step 3: the server use 'AA;BB;' and add NULL = NULL  
    -- Step 4: the value is null so the server use '' and add CC = CC  
    
    
    DECLARE @Name VARCHAR(1000)  
    SET @Name = ''  
    SELECT @Name = @Name + Name + ';'    
    FROM #temp  
    SELECT @Name AS Names   
    GO -- NULL   
    -- Why?  
    -- Using this approach the different is in step 4 since now we do not replace the NULL with '' and we have NULL + CC = NULL  
    

    Hope this was useful :-)

    Have great day guys

    💬Ronen Ariely

    Personal Site | Blog | Facebook | Linkedin

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.