Rolling up multiple rows into a single row and column for SQL Server data

By:   |   Updated: 2023-10-25   |   Comments (111)   |   Related: 1 | 2 | 3 | 4 | 5 | > TSQL


Problem

I need a way to roll-up multiple rows into one row and one column value as a means of concatenation in my SQL Server T-SQL code. I know I can roll-up multiple rows into one row using Pivot, but I need all of the data concatenated into a single column in a single row. In this tip we look at a simple approach to accomplish this.

Solution

To illustrate what is needed, here is a sample of data in a table from SQL Server Management Studio (SSMS):

Users per sector sales

This is an example of rolling up multiple rows into a single row. This is what we want the end result set to look like:

sample output

SQL Server T-SQL code to create the above result set by rolling up multiple rows into a single row using FOR XML PATH and the STUFF function:

SELECT 
   SS.SEC_NAME,
   STUFF((SELECT '; ' + US.USR_NAME 
          FROM USRS US
          WHERE US.SEC_ID = SS.SEC_ID
          FOR XML PATH('')), 1, 1, '') [SECTORS/USERS]
FROM SALES_SECTORS SS
GROUP BY SS.SEC_ID, SS.SEC_NAME
ORDER BY 1

Continue reading this SQL tutorial to learn about additional options and explanations for rolling up multiple rows into a single row.

How to Concatenate Multiple Rows into a Single Row in Microsoft SQL Server

Rolling up data from multiple rows into a single row may be necessary for concatenating data, reporting, exchanging data between systems and more. This can be accomplished by:

  • The solution proposed in this tip explores two SQL Server commands that can help us achieve the expected results. The SQL Server T-SQL commands used are STUFF and FOR XML.
  • The T-SQL STUFF command is used to concatenate the results together. In this example, a semi-colon is used as a separator for the results.
  • The FOR XML option for the SELECT command has four options (i.e. RAW, AUTO, EXPLICIT or PATH) to return the results. In this example, the PATH parameter is used to retrieve the results as an XML string.

Check out the example below to walk through the code samples and final solution to roll-up multiple rows into a single row in SQL Server.

Preparing Sample Data

Before we begin, we'll create some tables and sample data which the following script will do for us.

CREATE TABLE SALES_SECTORS(
SEC_ID INT,
SEC_NAME VARCHAR(30))
GO
CREATE TABLE USRS(
USR_ID INT,
USR_NAME VARCHAR(30),
SEC_ID INT
)
GO
CREATE TABLE ADV_CAMPAIGN(
ADV_ID INT,
ADV_NAME VARCHAR(30)
)
GO
CREATE TABLE USR_ADV_CAMPAIGN(
USR_ID INT,
ADV_ID INT
)
GO
CREATE TABLE SEC_ADV_CAMPAIGN(
SEC_ID INT,
ADV_ID INT
)
GO
INSERT INTO SALES_SECTORS( SEC_ID, SEC_NAME ) VALUES ( 1, 'ENTERTAINMENT' )
INSERT INTO SALES_SECTORS( SEC_ID, SEC_NAME ) VALUES ( 2, 'CLOTHES' )
GO
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 1, 'ANDERSON', 1 )
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 2, 'CHARLES', 1 )
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 3, 'DANNY', 1 )
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 4, 'LUCAS', 1 )
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 5, 'KEITH', 2 )
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 6, 'STEFAN', 2 )
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 7, 'EDUARD', 2 )
INSERT INTO USRS( USR_ID, USR_NAME, SEC_ID ) VALUES ( 8, 'BRAD', 2 )
GO
INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 1, 'SONY ENTERTAINMENT' )
INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 2, 'BEATS SOUNDS' )
INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 3, 'BOOSE' )
INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 4, 'POLO RALPH LAUREN' )
INSERT INTO ADV_CAMPAIGN( ADV_ID, ADV_NAME ) VALUES ( 5, 'LACOSTE' )
GO
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 1, 1 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 1, 2 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 2, 2 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 2, 3 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 3, 3 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 4, 2 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 5, 4 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 6, 5 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 7, 4 )
INSERT INTO USR_ADV_CAMPAIGN( USR_ID, ADV_ID ) VALUES ( 8, 5 )
GO
INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 1, 1 )
INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 1, 2 )
INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 1, 3 )
INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 2, 4 )
INSERT INTO SEC_ADV_CAMPAIGN( SEC_ID, ADV_ID ) VALUES ( 2, 5 )
GO

SQL Server STUFF() Function

Before going to the examples, we need to understand the workings of the commands mentioned above. The STUFF() function puts a string in another string, from an initial position. With this we can insert, replace or remove one or more characters.

This syntax is STUFF(character_expression, start, length, replaceWith_expression):

  • character_expression: string to be manipulated
  • start: initial position to start
  • length: number of characters to be manipulated
  • replaceWith_expression: characters to be used

Here is an example of the how to use the STUFF command.

For our example we have a single string that looks like this:

;KEITH;STEFAN;EDUARD;BRAD

We want to remove the first ; from the list so we end up with this output:

KEITH;STEFAN;EDUARD;BRAD

To do this we can use the STUFF command as follows to replace the first ; in the string with an empty string.

SELECT STUFF(';KEITH;STEFAN;EDUARD;BRAD', 1, 1, '')

And this returns this output as a concatenated string:

KEITH;STEFAN;EDUARD;BRAD

FOR XML Clause for the SQL Server SELECT Statement

The FOR XML clause, will return the results of a SQL query as XML. The FOR XML has four modes which are RAW, AUTO, EXPLICIT or PATH. We will use the PATH option, which generates single elements for each row returned.

If we use a regular query such as the following it will return the result set shown below.

SELECT 
   SS.SEC_NAME, 
   US.USR_NAME
FROM SALES_SECTORS SS
INNER JOIN USRS US ON US.SEC_ID = SS.SEC_ID
ORDER BY 1, 2
Users per sector sales

If we take this a step further, we can use the FOR XML PATH option to return the results as an XML string which will put all of the data into one row and one column.

SELECT 
   SS.SEC_NAME, 
   US.USR_NAME 
FROM SALES_SECTORS SS 
INNER JOIN USRS US ON US.SEC_ID = SS.SEC_ID 
ORDER BY 1, 2 
FOR XML PATH('')
sample output 4

SQL STRING_AGG Function to Rollup Data

In SQL Server 2017, the STRING_AGG function was introduced as a new option to rollup data. Check out these tips to learn more:

SQL Server Example to Rolling up Multiple Rows into a Single Row

Example 1

Now that we see what each of these commands does, we can put these together to get our final result.

The example query below uses a subquery where we are returning XML data for the USR_NAME from table USRS and joining this to the outer query by SEC_ID from table SALES_SECTORS. For each value from the inner query, we are concatenating a ";" and then the actual value to have all of the data from all rows concatenated into one column. We are grouping by SEC_NAME to show all USERS within that SECTOR.

SELECT 
   SS.SEC_NAME, 
   (SELECT '; ' + US.USR_NAME 
    FROM USRS US
    WHERE US.SEC_ID = SS.SEC_ID
    FOR XML PATH('')) [SECTORS/USERS]
FROM SALES_SECTORS SS
GROUP BY SS.SEC_ID, SS.SEC_NAME
ORDER BY 1

The below is the output for this query. We can see that we have the leading; in the SECTORS/USERS column which we don't want.

sample output 3

In this modified example, we are now using the STUFF function to remove the leading ; in the string.

SELECT 
   SS.SEC_NAME,
   STUFF((SELECT '; ' + US.USR_NAME 
          FROM USRS US
          WHERE US.SEC_ID = SS.SEC_ID
          FOR XML PATH('')), 1, 1, '') [SECTORS/USERS]
FROM SALES_SECTORS SS
GROUP BY SS.SEC_ID, SS.SEC_NAME
ORDER BY 1

And we get this result set:

sample output 2

If we also want to order the SECTORS/USERS data we can modify the query as follows:

SELECT 
   SS.SEC_NAME,
   STUFF((SELECT '; ' + US.USR_NAME 
          FROM USRS US
          WHERE US.SEC_ID = SS.SEC_ID
          ORDER BY USR_NAME
          FOR XML PATH('')), 1, 1, '') [SECTORS/USERS]
FROM SALES_SECTORS SS
GROUP BY SS.SEC_ID, SS.SEC_NAME
ORDER BY 1
sample output 5

Example 2

If we want this all to be in one column, we can change the query a little as follows:

SELECT 
   SS.SEC_NAME + ': ' +
   STUFF((SELECT '; ' + US.USR_NAME 
          FROM USRS US
          WHERE US.SEC_ID = SS.SEC_ID
          FOR XML PATH('')), 1, 1, '') [SECTORS/USERS]
FROM SALES_SECTORS SS
GROUP BY SS.SEC_ID, SS.SEC_NAME
ORDER BY 1

And this gives us this result:

Users concatenated by sale sectors

Example 3

This example takes it a step further where we have multiple subqueries to give us data based on USERS within CAMPAIGNS within SECTORS.

SELECT 
    SS.SEC_ID, 
    SS.SEC_NAME,
    STUFF((SELECT '; ' + AC.ADV_NAME + ' (' + 
             STUFF((SELECT ',' + US.USR_NAME
                    FROM USR_ADV_CAMPAIGN UAC
                    INNER JOIN USRS US 
                          ON US.USR_ID = UAC.USR_ID
                    WHERE UAC.ADV_ID = SAC.ADV_ID
                    FOR XML PATH('')), 1, 1, '') + ')'
           FROM ADV_CAMPAIGN AC
           INNER JOIN SEC_ADV_CAMPAIGN SAC 
                 ON SAC.ADV_ID = AC.ADV_ID AND SAC.SEC_ID = SS.SEC_ID 
           ORDER BY AC.ADV_NAME
           FOR XML PATH('')), 1, 1, '') [CAMPAIGNS/USERS PER SECTOR]
FROM SALES_SECTORS SS
GROUP BY 
     SS.SEC_ID, 
     SS.SEC_NAME
Users/Campaigns concatenated by sale sectors

Example Rolling Up Index Columns into One Row

Here is an example that will rollup indexes into one row and show the columns that are part of the index as well as included columns if any exist.

SELECT 
   SCHEMA_NAME(ss.SCHEMA_id) AS SchemaName,
   ss.name as TableName, 
   ss2.name as IndexName, 
   ss2.index_id,
   ss2.type_desc,
   STUFF((SELECT ', ' + name 
    from sys.index_columns a inner join sys.all_columns b on a.object_id = b.object_id and a.column_id = b.column_id and a.object_id = ss.object_id and a.index_id = ss2.index_id and is_included_column = 0
	order by a.key_ordinal
    FOR XML PATH('')), 1, 2, '') IndexColumns,
   STUFF((SELECT ', ' + name 
    from sys.index_columns a inner join sys.all_columns b on a.object_id = b.object_id and a.column_id = b.column_id and a.object_id = ss.object_id and a.index_id = ss2.index_id and is_included_column = 1
    FOR XML PATH('')), 1, 2, '') IncludedColumns
FROM sys.objects SS INNER JOIN SYS.INDEXES ss2 ON ss.OBJECT_ID = ss2.OBJECT_ID 
WHERE ss.type = 'U'
ORDER BY 1, 2, 3          

Conclusion

There are always several options to complete a task within SQL Server and we should take the time to explore the capabilities offered by the database before developing large and complex code. I hope this is one more of those examples that shows there are sometimes easier approaches than you think might be available.

Next Steps


sql server categories

sql server webinars

subscribe to mssqltips

sql server tutorials

sql server white papers

next tip



About the author
MSSQLTips author Douglas P. Castilho Douglas Castilho has been a SQL Server DBA over 6 years, focuses on tuning, backup, disaster recovery, mirroring, T-SQL, PL-SQL and .NET

This author pledges the content of this article is based on professional experience and not AI generated.

View all my tips


Article Last Updated: 2023-10-25

Comments For This Article




Thursday, April 4, 2024 - 3:15:00 PM - Gentre Back To Top (92150)
Thanks a bunch! This performed exactly what I needed done and very efficiently. Very, VERY helpful!

Wednesday, October 25, 2023 - 11:40:18 AM - Greg Robidoux Back To Top (91709)
Hi Valeriy,

there is another article that talks about STRING_AGG

https://www.mssqltips.com/sqlservertutorial/9371/sql-string-agg-function/

https://www.mssqltips.com/sqlservertip/5275/solve-old-problems-with-sql-servers-new-stringagg-and-stringsplit-functions/

-Greg

Wednesday, March 22, 2023 - 3:44:47 AM - Valeriy Yagudin Back To Top (91033)
Why didn't you include STRING_AGG?

Tuesday, April 26, 2022 - 4:50:50 PM - Ash Back To Top (90038)
Hello,

I'm trying generate payment advice message into 1 row right now it is showing multiple message lines.

This is code i'm using
%InsertSelect(RADV_DTL_TAO, PMT_INVOICE_TBL,RADVISE_KEY = C.PMT_ID, REFERENCE_FLD = A.INVOICE_ID, DATE1 = A.INVOICE_DT, PROCESS_INSTANCE = B.PROCESS_INSTANCE, CURRENCY_CD = A.PAID_AMT_CURRENCY, AMOUNT_1 = A.GROSS_AMT, AMOUNT_2 = A.PAID_AMT, AMOUNT_3 = A.DISCOUNT_TAKEN ,DESCR254 =substring(A.DESCR254_MIXED +CHAR(10)+D1.PYMNT_MESSAGE,1,254), PAY_DOC_ID = A.PAY_DOC_ID)
FROM PS_PMT_INVOICE_TBL A, ((PS_VOUCHER B1 LEFT OUTER JOIN PS_PYMNT_VCHR_MSG C1 ON B1.BUSINESS_UNIT = C1.BUSINESS_UNIT
AND B1.VOUCHER_ID = C1.VOUCHER_ID ) LEFT OUTER JOIN PS_PYMNT_MSG_LN D1 ON C1.PYMNT_MESSAGE_CD = D1.MESSAGE_CD
AND D1.PYMNT_MESSAGE <> ' '), %Table(PMT_STL_TAO) B , PS_PMT_DETAIL_TBL C , PS_PMT_SRC_DEFN D
ORDER BY D1.PYMNT_MESSAGE FOR XML PATH ('')
WHERE B.PROCESS_INSTANCE = %ProcessInstance
AND B.PMT_SOURCE = D.PMT_SOURCE
AND D.REMIT_ADVISE_OPT='Y'
AND A.PMT_ID = B.PMT_ID
AND C.PMT_ID = B.PMT_ID
AND B1.BUSINESS_UNIT = A.BUSINESS_UNIT
AND B1.INVOICE_ID = A.INVOICE_ID
AND B1.INVOICE_DT = A.INVOICE_DT

I'm getting an error
File: e:\pt85525b-retail\peopletools\src\psappeng\aedebug.hSQL error. Stmt #: 1723 Error Position: 0 Return: 8601 - [Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near 'PS_PM T_STL_TAO4'. [Microsoft][SQL Server Native Client 11.0][SQL Server]Statement(s) could not be prepared. (SQLSTATE 37000) 8180 Failed SQL stmt: INSERT INTO PS_RADV_DTL_TAO4 (PROCESS_INSTANCE, RADVISE_KEY, PARTY_ID, REFERENCE_FL D, SEQ_NBR, PAY_DOC_ID, DATE1, DATE2, DATE3, CURRENCY_CD, AMOUNT_1, AMOUNT_2, AMOUNT_3, AMOUNT_4, DE SCR254) SELECT B.PROCESS_INSTANCE, C.PMT_ID, ' ', A.INVOICE_ID, 0, A.PAY_DOC_ID, A.INVOICE_DT, NULL, NULL, A.PAID_AMT_CURRENCY, A.GROSS_AMT, A.PAID_AMT, A.DISCOUNT_TAKEN , 0, substring(A.DESCR254_MIXE
What i'm missing in the sql?
Thanks

Friday, April 8, 2022 - 5:04:04 PM - Greg Robidoux Back To Top (89982)
Hi Dana,

you could look at PIOVT and UNPIVOT

https://www.mssqltips.com/sqlservertip/1019/crosstab-queries-using-pivot-in-sql-server/
https://www.mssqltips.com/sqlservertip/2783/script-to-create-dynamic-pivot-queries-in-sql-server/

https://www.mssqltips.com/sqlservertip/3000/use-sql-servers-unpivot-operator-to-help-normalize-output/
https://www.mssqltips.com/sqlservertip/3002/use-sql-servers-unpivot-operator-to-dynamically-normalize-output/

-Greg

Friday, April 8, 2022 - 3:11:02 PM - Dana Shields Back To Top (89981)
Excellent article. But how do you do the opposite? i.e. expand multiple values in a single row/column into multiple rows?

Friday, April 8, 2022 - 3:07:33 PM - Dana Shields Back To Top (89980)
Excellent article, Rolling up multiple rows into a single row and column for SQL Server data.

But how do I then do the opposite further down my data flow (i.e. expand values in a single row/column into multiple rows)?

Thursday, November 4, 2021 - 5:14:31 AM - D James Back To Top (89407)
Excellent article, helped me solve a horrible report query I struggled with. Many thanks.

Monday, November 1, 2021 - 9:26:17 AM - iraj Back To Top (89390)
very good

Friday, June 18, 2021 - 1:10:01 AM - Peter Back To Top (88874)
Thanks so much, exactly what i need. Have previously used a heap of left joins and subqueries to achieve the same outcome, this is so much simpler and is dynamic.

Tuesday, May 25, 2021 - 7:34:20 AM - Alexa Back To Top (88735)
THIS HELPED ME A LOT

Tuesday, May 25, 2021 - 7:32:54 AM - Alexa Back To Top (88734)
Respected Sir

Here's a query I was trying to solve in mysql

roll subject grade

121 math A

121 phy C

121 eng A

122 math B

122 phy C

122 eng D



The required result is


roll math phy eng

121 A C A

122 B C D


Can you please kindly help me with this Sir?

Wednesday, May 5, 2021 - 2:33:48 PM - Kaitlyn Nohrenberg Back To Top (88650)
Hello,

This is the query I am working on, the goal is to have the correct locations for the individual part number but it looks like it is combining all the answers and every outcome is the same no matter the partnumber.

Select Distinct
PartNumber as 'Part',
Stuff ((Select distinct ', '+
Case When (a.Location like 'IM-%') then Stuff(a.location,1,3,'') else a.location end
From dbo.sublots as a
left join dbo.lots as b on a.LotNumberId= b.LotNumberId
left join dbo.parts as c on b.PartNumberId=c.PartNumberId
Where a.warehouse in ('Pr03')
and a.location is not null
and quantity > 0
For XML PATH('')), 1,2, '') as Location
From dbo.sublots as a
left join dbo.lots as b on a.LotNumberId= b.LotNumberId
left join dbo.parts as c on b.PartNumberId=c.PartNumberId
Where a.warehouse in ('Pr03')
group by PartNumber
order by PartNumber desc

What am I doing wrong

Thursday, March 11, 2021 - 2:35:15 PM - Greg Robidoux Back To Top (88379)
Hi Paul, see if the concepts in this article would help you: https://www.mssqltips.com/sqlservertip/6315/group-by-in-sql-sever-with-cube-rollup-and-grouping-sets-examples/

-Greg

Thursday, March 11, 2021 - 2:21:38 PM - Paul Back To Top (88378)
My last comment did not display correctly.

It should be listed as results:
column 1: Crayons
Column 2:
Red
Yellow
Blue

Each color would be on its own row, and each row in column 1 after Crayons would be empty. Much like an excel spreadsheet would look.


Wednesday, March 10, 2021 - 4:11:59 PM - Paul Back To Top (88375)
Hello,

I am using Oracle.

This was helpful, in a sense, but I am trying to create a report that lists the data like this:
TABLE_NAME TABLE_NAME
CRAYONS GREEN
RED
YELLOW
BLUE
PAPER BLACK
WHITE

I have not been able to find the answer anywhere and have had some trouble even wording it correctly to ask it...

Any help with that one would be much appreciated.

Thanks,
Paul

Tuesday, February 2, 2021 - 3:11:16 PM - Christian Henry Back To Top (88139)
Thank you Mr. Castilho, very good!

Wednesday, July 29, 2020 - 5:54:35 PM - Mary Back To Top (86213)

Thank you so much. This was a perfect solution for what I needed to do.


Sunday, July 26, 2020 - 5:35:52 PM - Barak Gal Back To Top (86194)

1. The XML PATH does not need a GROUP BY.

SELECT 
   SS.SEC_NAME, 
   (SELECT '; ' + US.USR_NAME 
    FROM USRS US
    WHERE US.SEC_ID = SS.SEC_ID
    FOR XML PATH('')) [SECTORS/USERS]
FROM SALES_SECTORS SS
ORDER BY 1

2. There is this great function from SQL 2017 and above: Simpler, more readable and less space for mistakes in syntax.

SELECT 
SS.SEC_NAME, 
STRING_AGG(US.USR_NAME,';')
FROM SALES_SECTORS SS 
INNER JOIN USRS US ON US.SEC_ID = SS.SEC_ID 
group by SS.SEC_NAME

Wednesday, July 8, 2020 - 9:57:26 AM - Greg Robidoux Back To Top (86106)

Hi Tom,

Thanks for the input.  There is also a tip on using string_agg - https://www.mssqltips.com/sqlservertip/5542/using-for-xml-path-and-stringagg-to-denormalize-sql-server-data/

-Greg


Wednesday, July 8, 2020 - 3:51:39 AM - Tom Peer Back To Top (86099)

This is great for <= 2016 but from 2017 you should avoid this techqniue and use STRING_AGG

https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15


Wednesday, April 15, 2020 - 12:02:36 PM - Adrian Parker Back To Top (85380)

Your SQL has an error. It will encode the resultting data witht XML markup. For instance, < will outtput as &lt;

Solve it by doing this (note the use of TYPE.value):

STUFF((SELECT '; ' + US.USR_NAME 
          FROM USRS US
          WHERE US.SEC_ID = SS.SEC_ID
          FOR XML PATH(''), TYPE.value('.', 'VARCHAR(MAX)'), 1, 1, '') [SECTORS/USERS]

Friday, April 10, 2020 - 2:22:32 PM - Greg Robidoux Back To Top (85335)

Here is an article that shows how to do this with STRING_AGG()

https://www.mssqltips.com/sqlservertip/5542/using-for-xml-path-and-stringagg-to-denormalize-sql-server-data/


Monday, April 6, 2020 - 11:35:09 AM - Jeff Moden Back To Top (85294)

I do realize that this article was first published in 2013 but, since it has been replished again here in 2020, please be advised that STRING_AGG() is the way to go on later versions of SQL Server.  Here's the link for the function.  Example "D" is what you want.  Example "C" is mislabled and isn't what you want.


Thursday, September 12, 2019 - 3:54:53 AM - Shyamji Yadav Back To Top (82379)

1000135  10
1000135  9
1000135  9458
1000135  8
1000135  74
1000135  6
1000168  75
1000168  42
1000168  74

I am using the 2nd example query however, I can't get the desired output.

Kindly help with the same 

The query i used is

SELECT 
   SS.SM1,
   STUFF((SELECT '; ' + US.SM2 
          FROM #temp2 US
          WHERE US.SN2 = SS.SN1
          ORDER BY SM2
          FOR XML PATH('')), 1, 1, '') [Symbols]
FROM #temp1 SS
GROUP BY SS.SN1, SS.SM1
ORDER BY 1

Monday, August 26, 2019 - 2:35:19 PM - Synergy Back To Top (82142)

I've a csv file which contains data with new lines for a single row i.e. one row data comes in two lines and I want to insert the new lines data into respective columns. I've loaded the data into sql but now I want to replace the second row data into 1st row with respective column values.

ID Name Department DOB State Country Salary

1 Mohammed IT 2019-08-12 Odisha India 2000

2 Dinesh CS 2015-06-19 Andhra India 2500

3 Naveen CH

2016-03-08 Andhra India 3200

4 Mohan ME 2012-10-11 Telangana India 2080

5 Shankar AE 2014-04-17

Telangana India 3000

 

I want the output like:

ID Name Department DOB State Country Salary

1 Mohammed IT 2019-08-12 Odisha India 2000

2 Dinesh CS 2015-06-19 Andhra India 2500

3 Naveen CH 2016-03-08 Andhra India 3200

4 Mohan ME 2012-10-11 Telangana India 2080

5 Shankar AE 2014-04-17 Telangana India 3000


Monday, July 1, 2019 - 3:14:53 PM - Greg Robidoux Back To Top (81652)

Hi Kelly,

Does the query work in SQL Server Management Studio?

Not sure what version of SQL Server you are using, but you could also look at the new STRING_AGG function.

https://www.mssqltips.com/sqlservertip/5275/solve-old-problems-with-sql-servers-new-stringagg-and-stringsplit-functions/

-Greg


Monday, July 1, 2019 - 1:47:59 PM - Kelly Welch Back To Top (81651)

I am not able to get this to work.  I need to put this select into the Envision Argos Report generator and it is erroring out there.  So, I put it inthe Toad took and it doesn't like the FOR XML so, is there another way to do this?  This is where it has to live so my hands are tied.

Here is my code:

select distinct
       spriden_id,
       sgbstdn_term_code_eff,
       spriden_first_name,
       spriden_last_name,
       sgbstdn_styp_code,
       (SELECT '/' + gorrace_desc
               FROM gorprac, gorrace
               WHERE spriden_pidm = gorprac_pidm
               and gorprac_race_cde = gorrace_race_cde
               FOR XML PATH(''))
       from spriden, sgbstdn
       where spriden_pidm = sgbstdn_pidm
       and sgbstdn_styp_code = '1'
       and sgbstdn_term_code_eff in (201750,201770,201810,201830)
order by 1,2


Sunday, June 30, 2019 - 7:24:09 PM - Chandu Back To Top (81642)

I have tried example 1. However, my data is not rolling up.

My code:

SELECT o.Ord_ID,

stuff((select ';' + fr.FrtRule_Description

from  Freight_Rules as fr

where fr.FuelFrtRule_Key=o.LoadFrt_FrtRule_Key

for xml path('')),1,1,'') as Freight_Rule

from Orders as o

group by o.LoadFrt_FrtRule_Key,o.Ord_Key

order by 1;

Any help?


Monday, June 10, 2019 - 7:28:45 AM - Patrick McDaniel Back To Top (81398)

Excellent work with demonstrations. Your title is great also as I seriously didn't think I would find anything like this to help me out.


Wednesday, June 5, 2019 - 9:20:37 AM - Graeme Buss Back To Top (81335)

 Hi Douglas,

This really assisted me on getting Duplicated entries. Now I need to try and Merge the Duplicated entries into "one version of the truth"

eg. 

PrimaryOrganizationID Name DuplicatedIDs

3645994 'Duplicated Organization' 2952208, 2954445, 3348152, 3356275, 3549114, 3645994, 3302925

Is there a way to generate an update script to update all duplicated issues with the primary ID across many tables?

Regards

Graeme


Thursday, May 23, 2019 - 3:26:05 AM - Kantor Andras Back To Top (80163)

Thank you very much, it helped me a lot.


Sunday, April 7, 2019 - 4:49:05 PM - Will Back To Top (79495)

Douglas - Thank you so much for your time and effort putting this information out here.  Your examples are clear and easy to follow.


Tuesday, March 19, 2019 - 12:21:42 PM - Tammy Robinson Back To Top (79339)

 I am using the below to get type of pets. If there is no Pet, I want 'N/A' to be displayed. How can I incorporate this into the below statement?

  STUFF((SELECT CASE WHEN COUNT(pp.sPetType) = 1 and pp.sPetIsServiceAnimal = 'No' then '; ' + '1 ' + pp.sPetType  ELSE
          CASE WHEN COUNT(pp.sPetType) = 2 and pp.sPetIsServiceAnimal = 'No' then '; ' + '2 ' + pp.sPetType  + 's' ELSE
          CASE WHEN COUNT(pp.sPetType) = 3 and pp.sPetIsServiceAnimal = 'No' then '; ' + '3 ' + pp.sPetType + 's'
          END END END
          FROM person_pet pp
          WHERE t.hMyPerson = pp.hMyPerson
          GROUP BY pp.sPetType, pp.sPetIsServiceAnimal
          FOR XML PATH('')), 1, 1, '')[PetType]

Thank you


Friday, January 4, 2019 - 1:50:19 PM - Anitha Maramreddy Back To Top (78630)

 Thank you so much for your tip. This helped me:)


Thursday, September 27, 2018 - 5:34:22 AM - Surya Gopal Back To Top (77741)

 This is a nice solution provided, much thanks to the author :)


Wednesday, August 1, 2018 - 5:16:42 AM - Govardhan Katta Back To Top (76924)

 Hi,

There is another easy way to achieve these functionality. for eaxmple, the above Example 2 can be do in the following way to acheive the same output.

SELECT 

   SS.SEC_NAME,

 (SELECT STRING_AGG (US.USR_NAME, ';') 

FROM USRS US WHERE US.SEC_ID = SS.SEC_ID) [SECTORS/USERS]

FROM SALES_SECTORS SS

GROUP BY SS.SEC_ID, SS.SEC_NAME

ORDER BY 1


Sunday, April 8, 2018 - 9:28:58 AM - sudartis Back To Top (75640)

 

 why it's error. in code for XML PATH ('')


Thursday, December 21, 2017 - 2:07:09 AM - @altzus Back To Top (74292)

+1 

Thanks! 

 

 


Thursday, December 14, 2017 - 3:35:46 AM - Shailendra Back To Top (73993)

 

 Thanks,

Really helpfull :)  


Monday, October 30, 2017 - 3:57:05 AM - pooja Back To Top (68958)

Can u plz help to writ a query to get the follwing result shown in ex.b

ex.a)

Emp_id  Salary

1           1000

2           1000 

3           2000

4           2000

5           3000

--------------------------------

ex.b)

Emp_id  Salary

1           1000

2          

3           2000

4           

5           3000


Wednesday, October 11, 2017 - 5:51:43 AM - Benny Back To Top (67189)

Hello,

Thanks a lot for this article it helped me out quite a lot! 

 


Tuesday, July 25, 2017 - 2:37:18 PM - Vasu Back To Top (63226)

 Hello,

This is a very good article. It helped me a lot.

 

Thanks

Vasu

 


Thursday, February 23, 2017 - 12:58:48 PM - Melaku Kore Back To Top (46623)

 Hello, am doing on machine trnasliteration for master thesis , so how can we combine if the user input string on text box and the character mappings stored on different rows the table. How i can concatinate and disply them?

 


Wednesday, February 15, 2017 - 5:12:31 AM - Jan Michael Nuqui Back To Top (46352)

 

Thanks for this code! Thanks to google as well as I typed "how to gather all information of a column to a one column" as I didn't really know what the logic I want is called. haha So the process is called roll up.

 

Thank you very much for this info!


Friday, November 11, 2016 - 5:43:17 AM - Brijesh Back To Top (43744)

 Please help me with below condition.

I am having SectorName and UserName
SNO ID SECTOR_NAME USERNAME

1      101    Cloths                AAA

2      101    Entertainment     BBB

3      101    Drinks                CCC

4      101    Cloths                DDD

5      222    Cloths                EEE

6      433    Entertainment     FFF 

7      101    Entertainment     GGG

8      222   Drinks                HHH

Required Result:
foR id 101

SNO   CLOTHS          ENTERTAINMENT

 1.         AAA,DDD     BBB,GGG


Wednesday, June 1, 2016 - 10:27:11 AM - Don Goodrich Back To Top (41592)

 This example works great for me, it rolls-up the file correctly.

I do however, need to set values for the merged fields (like an array) so the application that will use this file can determine how many appointments need to be sent to the customer.  I've reviewed the articles and none of them can answer this question.

 


Friday, May 27, 2016 - 4:52:16 PM - Trevor Back To Top (41576)

Thank you for the clear explanation -- it's helped me twice now.

Now my comment: The code as written removed the leading semicolon, but leaves a leading space in front of the concatenated string.  To fix it, simply adjust the STUFF command telling it to cut off two characters:

STUFF(<text/query>, 1, 2, '')

 


Monday, April 4, 2016 - 10:06:00 PM - Kenneth Tan Back To Top (41134)

Thanks a lot Sir!


Monday, March 28, 2016 - 4:08:42 AM - Anon Back To Top (41069)

Previously I really struggled to grasp how to implement this concept - finally with your post it makes sense.


Wednesday, March 16, 2016 - 2:53:04 PM - John Spencer Back To Top (40961)

 I will say, I never thought I would what is discussed above; however, the above has helped to 'extricate me from several nettles of danger.'  And, thanks for the detailed explanations. 

I will confess to using 'STUFF and the XML portion without really what they did.

 


Sunday, February 28, 2016 - 1:24:19 AM - Christian Albite Back To Top (40815)

Hi there. Thanks for the tip. But I have just one issue. I am working on my thesis. Back to my problem, waht if I want to create multiple columns for Users. One column for SEC_NAME, and individual colums for SECTORS/USERS. For example, 1 column cell for Clothes, 1 cell for Keith, other 1 for Stefan, and so on.

SEC_NAME             Sector1        Sector2        Sector3        Sector 4
Clothers                 Keith            Stefan         Eduard         Brad
Entertainment         Anderson     Charles        Danny          Lucas

Well, hoping I could find answers. Thank you. :D 

- Christian

 


Friday, February 19, 2016 - 1:54:43 PM - David Jacobson Back To Top (40733)

Doug, thanks for the tip, great stuff (no pun).  I do have a slight issue maybe you could help me with.  My query is not in the right order and I'm not sure how to fix it.  So when my query runs, it gets 5 records like such:

workID     cid     comment
100           2       Test 2
100           3       Test 3
100           5       Test 5
100           4       Test 4
100           1       Test 1

So, I want to get the two most recent comments for record 100 into 1 field.  But now I am getting cid 2,3 and NOT 4,5.  Does that make sense?  When I add the cid to the group by statement I get 6 of the same records.  ARGH!  Can you point me in the right direction?

 David


Wednesday, January 20, 2016 - 8:29:26 AM - laurent Back To Top (40452)

 

Thank you for this very explicit, simple and effective tip.

It Solved my problems in a few minutes.

Best regards


Wednesday, December 16, 2015 - 9:20:47 AM - Wojciech Back To Top (40253)

Hi,

Great article. It helped me to perform my task I got from my boss today and he is enchanted with what I have done thanks to you!

Thanks a lot.

Wojciech


Friday, November 20, 2015 - 6:29:14 AM - Shailesh Rabari Back To Top (39110)

It's Very Nice.

Useful Content.


Thursday, October 15, 2015 - 9:46:43 AM - Matt Back To Top (38902)

several years later and this is still relevant.  Thanks!


Wednesday, October 7, 2015 - 5:04:56 AM - Thomas Franz Back To Top (38834)

Your syntax has a problem, if the text data contains < or >:

If you

UPDATE ADV_CAMPAIGN SET ADV_NAME = '<SONY> <!--> <ENTERTAINMENT>' WHERE ADV_ID = 1

then your last query will return

 &lt;SONY&gt; &lt;!--&gt; &lt;ENTERTAINMENT&gt; (ANDERSON); BEATS SOUNDS (ANDERSON,CHARLES,LUCAS); BOOSE (CHARLES,DANNY)

If you would replace the FOR-XML-lines by

            FOR XML PATH('i'), root('c'), type
                  ).query('/c/i').value('.', 'varchar(8000)'), 1, 1, '') [CAMPAIGNS/USERS PER SECTOR]
it would return the correct 
 <SONY> <!--> <ENTERTAINMENT> (ANDERSON); BEATS SOUNDS (ANDERSON,CHARLES,LUCAS); BOOSE (CHARLES,DANNY)

instead (feel free to use varchar(max) if necessary).


Friday, September 4, 2015 - 8:41:44 AM - VIJAY Back To Top (38599)

Hi ,

 

The data returned for the xmlpath using stuff function returns a lenght of  45678 .

 

But if it is used in the xmlpath it is generating all the rows.

 

select a.col1,+',' from  a 

for xml path('')

This returns all the rows.

 

select stuff((select a.col1,+',' from  a 

for xml path('')),1,1,'') as b

This returns 45678  lenght of data 

 

could you help in resolving this issue

 

 

 


Thursday, August 13, 2015 - 5:30:58 AM - Ying Back To Top (38437)

Thank you.  It's exactly what I looking for. :)


Wednesday, July 8, 2015 - 4:29:25 PM - davidh Back To Top (38158)

would be nice to have people put very vanilla query using the functions they share. too much going on and someone like myself, newbie, needs to understand basics on it and how to use it plain and simple to take a column with multiple values and place it into one single cell (one column and one row) as the output with comma separation in the next step following.

greatly appreciate anything. thank you.


Friday, June 12, 2015 - 1:03:34 PM - Mena Dawoud Back To Top (37907)

Excellent;

but this just in SQL Server Management Studio,

As for Visual Studio it also shows the name of the XML tag <> & </>


Tuesday, June 2, 2015 - 12:35:29 PM - glauco guerrero Back To Top (37363)

Thanks  for your solution and taking the time for explaining this tip.

 

 

 


Monday, May 4, 2015 - 8:26:02 PM - Dougal Back To Top (37089)

Fantastic explanation, thankyou!


Thursday, March 12, 2015 - 5:04:55 AM - Pacha Back To Top (36504)

Thank you!

You guide help me a lots !!


Tuesday, March 3, 2015 - 8:28:47 AM - Squeezer Back To Top (36416)

Thanks Douglas for this excelent guide! It's exacly what i was looking for! 

 


Tuesday, January 27, 2015 - 5:40:16 PM - Frankie Back To Top (36078)

Thank you Douglas for this tip,

I have been scouring the web on how to do exactly this. With no luck I gave up, months later while researching SQL stuff, I stumbled upon this link and it was exactly what I needed months ago. Now I have this knowledge under my belt all thanks to you. Thank you!


Tuesday, December 30, 2014 - 6:52:29 PM - Payam Back To Top (35792)

Thank you so much! It really helped me and that was what I was searching for... :) Have a nice day.


Tuesday, December 2, 2014 - 3:39:42 AM - Athirah Back To Top (35455)

HI Douglas. This is a great code. Howevder, I get this error :

Conversion failed when converting the varchar value '; ' to data type int. 

I've tried everything and still its not working.


Friday, November 7, 2014 - 12:59:06 AM - Kavin Back To Top (35216)

I want for real number the stuff command works only for variables


Thursday, November 6, 2014 - 2:35:56 PM - Luna Back To Top (35205)

This is exactly what I have been searching for weeks! Thank you. Works perfectly with SSMS.


Saturday, October 25, 2014 - 2:07:43 AM - Dr Mohamed Bekheit Back To Top (35061)

Dear Author Castilho,

Thank you for your useful tips published online.

I have one simple question that is bothering me so much, since I am a physician and have no big experience in sql (not even small) .

I need to recover data from our web based database. There are multiple records with the same name (because we repeat experiments for the same subject, but each experiment is in a separate row), so there will be several rows concerning one person but containes different data. I need while exporting the data to have a single row for each record that contains all information.

I will copy to you the automated query generated by the interface:

SELECT patient.nom AS 'Nom', patient.poids AS 'Poids', biology.date_consultation AS 'Measurement date', biology.heure_GDS AS 'Hour', biology.timemesure AS 'Time of measurement (before hpx ...)', biology.jour AS 'Day (J-7/J0 ...)', biology.chk_blood_type1 AS 'Arterial Blood', biology.pCO2 AS 'pCO2 mmHg', biology.pO2 AS 'pO2 mmHg', biology.SO2 AS 'sO2 %', biology.Hb AS 'Hb g/dL', biology.Htc AS 'Htc %', biology.Na AS 'Na mmol/L', biology.K AS 'K mmol/L', biology.Ca AS 'Ca mmol/L', biology.Lac AS 'Lactates mmol/L', biology.Glu AS 'Glu (glycemia)', biology.chk_blood_type2 AS 'Venous Blood', biology.pCO2_vein AS 'pCO2 mmHg', biology.pO2_vein AS 'pO2 mmHg', biology.SO2_vein AS 'sO2 %', biology.pH_vein AS 'pH val abs', biology.Hb_vein AS 'Hb g/dL', biology.Htc_vein AS 'Htc %', biology.Na_vein AS 'Na mmol/L', biology.K_vein AS 'K mmol/L', biology.Ca_vein AS 'Ca mmol/L', biology.Lac_vein AS 'Lactates mmol/L', biology.Glu_vein AS 'Glu (glycemia)', biology.chk_blood_type3 AS 'Mixt Venous Blood', biology.pCO2_veinMix AS 'pCO2 mmHg', biology.pO2_veinMix AS 'pO2 mmHg', biology.SO2_veinMix AS 'sO2 %', biology.pH_veinMix AS 'pH val abs', biology.Hb_veinMix AS 'Hb g/dL', biology.Htc_veinMix AS 'Htc %', biology.Na_veinMix AS 'Na mmol/L', biology.K_veinMix AS 'K mmol/L', biology.Ca_veinMix AS 'Ca mmol/L', biology.Lac_veinMix AS 'Lactates mmol/L', biology.Glu_veinMix AS 'Glu (glycemia)', biology.date_consult_labo AS 'Measurement date', biology.heure_labo AS 'Hour', biology.timelabo AS 'Time of measurement (before hpx ...)', biology.jourlabo AS 'Day (J-7/J0 ...)', biology.NA_labo AS 'Na mmol/L', biology.K_labo AS 'K mmol/L', biology.Cl AS 'Cl mmol/L', biology.CO2_labo AS 'CO2', biology.Creatinine AS 'Creatinine µmol/L', biology.Uree AS 'Uree mmol/L', biology.Glycemie AS 'Glycemie mmol/L', biology.Lactates AS 'Lactates mmol/L', biology.Proteines AS 'Proteines g/L', biology.ASAT AS 'ASAT Ul/l', biology.ALAT AS 'ALAT Ul/l', biology.Bili_tot AS 'Bilirubine totale µmol/L', biology.Bili_conj AS 'Bilirubine conj µmol/L', biology.Bili_lib AS 'Bilirubin libre µmol/L', biology.Gamm_GT AS 'Gamma GT Ul/l', biology.Phosphatase_Alcaline AS 'Phosphatase Alcaline Ul/l', biology.Hemoglo AS 'Hemoglobine g/dl', biology.Hemato AS 'Hematocrite %', biology.Leuco AS 'Leucocytes -/mm3', biology.Plaquettes AS 'Plaquettes -/mm3', biology.TP AS 'TP (taux de prothrombine) %', biology.timeTP AS 'time TP (sec)', biology.timeTPtemoin AS 'time temoin TP (sec)', biology.TCA AS 'TCA (temps de cephaline active) val abs', biology.timeTCA AS 'TCA time (sec)', biology.timeTCAtemoin AS 'TCA time temoin (sec)', biology.INR AS 'INR (internation normalized ratio) val abs', biology.Ammo AS 'Ammoniemie µmol/L'

FROM patient, biology

 

WHERE biology.ID_patient = patient.ID_patient


Thursday, October 23, 2014 - 4:45:41 PM - Slow roll Back To Top (35047)

--This is a great time saver and great code- thank you!

 


Wednesday, October 22, 2014 - 10:59:54 AM - Lisa Back To Top (35036)

 

 

Dude you just increased my quality of life!!!!!


Wednesday, October 15, 2014 - 3:57:59 AM - John Back To Top (34964)

Excellent post, thanks very much for sharing.


Tuesday, October 7, 2014 - 4:05:58 PM - Ygg Meanhorse Back To Top (34871)

Very well done artical. I learned some stuff. Thanks a lot.


Monday, September 29, 2014 - 10:40:19 PM - po Back To Top (34766)

Thank you so much and your article is so helpful but I have 1 question. 

I wrote an SQL statement with STUFF and FOR XML function and try to put it into MS Query in Excel, but I found it's not working.  Is it STUFF and FOR XML function is not compatable in excel ms query?  If so, are there any other SQL functions I can use to achieve the same results and is compatable in excel ms query?

Thanks a lot for your help. 

Regards,

Po


Wednesday, July 23, 2014 - 10:50:51 PM - Zaigham Back To Top (32849)

Hi Douglas,

   Thank you so much for creating this excellent article and sharing your knowledge. It was very concise and to the point. Thank you :-)


Tuesday, June 24, 2014 - 1:23:09 PM - Douglas Back To Top (32374)

Hi sanil, please follow this example ok:

DECLARE @EMAIL VARCHAR(30)
SET @EMAIL = '[email protected]'
SELECT SUBSTRING(@EMAIL, 1, PATINDEX('%@%',@EMAIL)-1) NAME,
       SUBSTRING(@EMAIL, PATINDEX('%@%',@EMAIL)+1, LEN(@EMAIL)-PATINDEX('%@%',@EMAIL)) DOMAIN

You can change the parameter @EMAIL by your table field ok.

Thank you.

Douglas.


Tuesday, June 24, 2014 - 3:23:22 AM - sunil Back To Top (32367)

Q) a table consisting of single column like

    [email protected]

    [email protected]

    [email protected]

 if this above is the situation ,the answer should contain two columns

name     mailid

sunil       sunmail.com

lava        sunmail.com

bhanau   bhanumail.com

what query we have to write to get the above result ..plz help me sir.

thnks in advance


Thursday, May 22, 2014 - 9:47:19 AM - Parimal Back To Top (30885)

That was very helpful :) Thanks for that :)

 

Best regards,

Parimal


Tuesday, April 8, 2014 - 6:52:14 AM - Suganya Back To Top (30002)

Great...It was very helpful


Monday, March 24, 2014 - 3:23:50 AM - Satish Back To Top (29841)

Thank you Douglas for the nice article !


Thursday, January 23, 2014 - 9:15:19 PM - Douglas P. Castilho Back To Top (28204)

Hi talal, what you need is this ?

 

declare @T table (Name nvarchar(50), Friends nvarchar(50))

insert into @T values 

('Joe','Jean'),

('Mike','Jean'),

('Jean','Zaki'),

('Zaki','Ali'),

('Mimi','Nana'),

('Chico','Yari')

 

DECLARE @F table (FriendsOfJoe nvarchar(50))

DECLARE @INDEX INT = (SELECT COUNT(*) FROM @T)

WHILE (@INDEX >= 1)

BEGIN

INSERT INTO @F (FriendsOfJoe) SELECT Friends FROM @T WHERE Name = 'Joe' AND NOT EXISTS (SELECT 1 FROM @F WHERE FriendsOfJoe = Friends)

INSERT INTO @F (FriendsOfJoe) SELECT Friends FROM @T WHERE Name IN (SELECT FriendsOfJoe FROM @F) AND NOT EXISTS (SELECT 1 FROM @F WHERE FriendsOfJoe = Friends)

INSERT INTO @F (FriendsOfJoe) SELECT Name FROM @T WHERE Friends IN (SELECT FriendsOfJoe FROM @F) AND NOT EXISTS (SELECT 1 FROM @F WHERE FriendsOfJoe = Name) AND Name <> 'Joe'

SELECT @INDEX -= 1

END

 

SELECT * FROM @F

----------------------
 
Thank you!
 

Thursday, January 23, 2014 - 8:32:13 PM - Douglas P. Castilho Back To Top (28203)

Hi saadee,

What you need is something like this?

 

CREATE TABLE TEST (

COL CHAR(1) )

 

INSERT INTO TEST (COL) VALUES ('A')

INSERT INTO TEST (COL) VALUES ('B')

INSERT INTO TEST (COL) VALUES ('C')

INSERT INTO TEST (COL) VALUES ('D')

INSERT INTO TEST (COL) VALUES ('E')

INSERT INTO TEST (COL) VALUES ('F')

INSERT INTO TEST (COL) VALUES ('g')

INSERT INTO TEST (COL) VALUES ('H')

INSERT INTO TEST (COL) VALUES ('I')

INSERT INTO TEST (COL) VALUES ('J')

 

DECLARE @INDEX INT = 1

DECLARE @COLS VARCHAR(20) = 

(

SELECT 

   DISTINCT

   STUFF((SELECT UPPER(TB2.COL)

          FROM TEST TB2

          FOR XML PATH('')), 1, 0, '') COL

FROM TEST TB1

)

 

SELECT SUBSTRING(@COLS, @INDEX, 1) AS COL1,

       SUBSTRING(@COLS, @INDEX + 1, 1) AS COL2,

  SUBSTRING(@COLS, @INDEX + 2, 1) AS COL3

UNION ALL

SELECT SUBSTRING(@COLS, @INDEX + 3, 1) AS COL1,

       SUBSTRING(@COLS, @INDEX + 4, 1) AS COL2,

  SUBSTRING(@COLS, @INDEX + 5, 1) AS COL3

UNION ALL

SELECT SUBSTRING(@COLS, @INDEX + 6, 1) AS COL1,

       SUBSTRING(@COLS, @INDEX + 7, 1) AS COL2,

  SUBSTRING(@COLS, @INDEX + 8, 1) AS COL3

UNION ALL

SELECT SUBSTRING(@COLS, @INDEX + 9, 1) AS COL1,

       SUBSTRING(@COLS, @INDEX + 10, 1) AS COL2,

  SUBSTRING(@COLS, @INDEX + 11, 1) AS COL3

 
Let me know if this simple example helped you ok.
Thanks!!!

Thursday, December 19, 2013 - 2:42:11 AM - Alekhya Back To Top (27842)

 

I have one question:

 

My case is :

 

Contract     R/I                   LCEAMTSURP     

Number      Account                              

                  No                                   

03005909  MR03FR                 2,300,000     

03005909  13FRST1                        0     

03005909  13PPXL2                        0     

03005909  13PPXL3                        0     

 

Now i need this format in teh below way in order to remove the duplicate data:

 

Contract Number      MR03FR | 13FRST1 | 13PPXL2 | 13PPXL3

03005909                2,300,000| 0 | 0 | 0

 

How can i do this? Please do help.... 


Friday, December 13, 2013 - 4:30:46 PM - rodrigo Back To Top (27796)

Great article!

 

 


Saturday, November 2, 2013 - 11:54:26 AM - talal Back To Top (27374)

Hello

I have a table containing 2 columns describing friendship relations

declare @T table (Name nvarchar(50), Friends nvarchar(50))

insert into @T values 

('Joe','Jean'),

('Mike','Jean'),

('Jean','Zaki'),

('Zaki','Ali'),

('Mimi','Nana'),

('Chico','Yari')

...

My question is how to get the integral list of friend of Joe (Joe,Jean,Mike,Zaki,Ali) using Sql Server

Thanks in advance


Saturday, October 19, 2013 - 6:13:29 AM - Baiju Back To Top (27196)
  1. in time and out time from query

02-20-2013 12:18 PM|LINK

I have a  table Events

Events containing

cardno,time,id,name--each id has a cardno



my requirement is every day each employee swipe the card several times

i want to calculate first and last time of each card

the output should be

name     1                       2                             6        7  
           in       out            in        out                    holiday   holiday
xxx      09:30     06:30      09:40   06:45
where 1,2...... are dates for example january 1,2, etc. 6 and 7 are saturday and sunday

how it is posssible

Regards
Baiju


Thursday, October 3, 2013 - 2:06:14 PM - saadee Back To Top (27027)

hi sir.i want to convert single column into multiple columns.

here is the table structure

------- create a table having single column
--- col whose data is A,B,C,D,E,F,G,H,I,J
---- WRITE A QUERY TO GET AN OUTPUT AS
----- COL1    | COL2    | COL3
-------    A        B        C
--          D        E        F
--          G        H        I
--          J        NULL    NULL

help out to solve or mail me answer on [email protected]


Tuesday, August 13, 2013 - 11:14:44 AM - Douglas P. Castilho Back To Top (26280)

Hi alotus,

I don´t know if the code below help you, because I don´t have more details about your needs, but I think you can understand what we can do with the code below, I´ll wait your feedback, I hope to have helped you.

 

CREATE TABLE #Tb_A(

COL_1 VARCHAR(100),

COL_2 INT

)

 

INSERT INTO #Tb_A(COL_1, COL_2) VALUES ('A11 Perth, Australia AP-PERTH; AP-PERTHBAN', 128)

INSERT INTO #Tb_A(COL_1, COL_2) VALUES ('A11 Perth, Australia AP-PERTH; AP-PERTHBAN', 282)

 

SELECT 

   STUFF((SELECT DISTINCT A.COL_1 + ' ' + 

          (SELECT CAST(SUM(B.COL_2) AS VARCHAR) FROM #Tb_A B WHERE B.COL_1 = A.COL_1) as "text()"

          FROM #Tb_A A

          FOR XML PATH('')), 1, 1, '') RESULT

 

DROP TABLE #Tb_A

This simple example returned:

11 Perth, Australia AP-PERTH; AP-PERTHBAN 410

 

Thank you.

Have a great day!


Thursday, August 8, 2013 - 12:48:27 PM - alotus Back To Top (26149)

Hi - This is great! Thank you!

However, I'm hoping you can help me with one thing:

I have used your SQL code to do what I need to for the most part with my DB, but if I need to add a count column and sum the results, I'm not sure how to do that. For example, let's say I return the following: 

A11Perth, AustraliaAP-PERTH; AP-PERTHBAN

If I add in a count column at the end of the select query, it displays the following:

A11 Perth, Australia AP-PERTH; AP-PERTHBAN 128 A11 Perth, Australia AP-PERTH; AP-PERTHBAN 282

What I really need is for it to look like the 1st output, but have 128 and 282 summed into 410. This is just one example with two results. I have a few other examples in the same table where there are as many as 10 or 12 rows that need to be summed.

Any thoughts? Thanks!


Thursday, August 8, 2013 - 12:38:32 PM - Miles Back To Top (26148)

I am currently in a situation where I need to get a comma delimited file created. I need to evaluate users based on matching SSNs, but not matching member codes. This determines if the base user has a spouse, and/or children. I would then need this to add up to some value, based on matching SSNs, and assign the appropriate number if the SSNs match, but the member codes do not. For example, the base user would have a value of "1", while the spouse would have a value of "2", so for the sake of this process, they would have a total value of "3", and then I would need to assign the appropriate field value to a flat file using SSIS. Adding to this is those with 4 or 5 children, thus having 6 or 7 records to evaluate. This can get even trickier if there are matching SSNs, with not matching member codes, but then also that they do not share the same termination date. This means that one person, either a spouse or dependent, is no longer considered part of that "family group", thus have a different value assigned to them than the rest of the "family".

 

I thought about rewriting the VB code from the original application, but this has become a huge undertaking, since it was setup to create an xml file using an array, so I setup an SSIS package for this instead. I have most of it completed, but how to populate the one field is stumping me. I thought about using a Cursor, but I may have to evaluate up to 6 or 7 rows, depending on how many children are involved, so I am not sure if this is going to work or not.

 

Does anyone have any suggestions on where to start with getting SQL code together that can accomplish this?


Wednesday, July 31, 2013 - 9:59:43 AM - tCubeR Back To Top (26070)


--for the reporting I like the astric delimiter:
--===============================================

SELECT
    SS.SEC_ID,
    SS.SEC_NAME,
    STUFF((SELECT '*' + AC.ADV_NAME + ' (' +
             STUFF((SELECT ',' + US.USR_NAME
                    FROM USR_ADV_CAMPAIGN UAC
                    INNER JOIN USRS US
                          ON US.USR_ID = UAC.USR_ID
                    WHERE UAC.ADV_ID = SAC.ADV_ID
                    FOR XML PATH('')), 1, 1, '') + ')'
           FROM ADV_CAMPAIGN AC
           INNER JOIN SEC_ADV_CAMPAIGN SAC
                 ON SAC.ADV_ID = AC.ADV_ID AND SAC.SEC_ID = SS.SEC_ID
           ORDER BY AC.ADV_NAME
           FOR XML PATH('')), 1, 1, '') [CAMPAIGNS_USERS_PER_SECTOR]
FROM SALES_SECTORS SS
GROUP BY
     SS.SEC_ID,
     SS.SEC_NAME

;


--in your SSRS report add a field with an expression:
--=======================================================

--set expression for:
/*
=IIf(Len(Fields!CAMPAIGNS_USERS_PER_SECTOR.Value) > 0, Replace(Fields!CAMPAIGNS_USERS_PER_SECTOR, "*", vbCrLf), "")


Results:
--===========================
CAMPAIGNS_USERS_PER_SECTOR

BEATS SOUNDS (ANDERSON,CHARLES,LUCAS)
BOOSE (CHARLES,DANNY)
SONY ENTERTAINMENT (ANDERSON)

*/

 


Tuesday, July 16, 2013 - 6:19:24 AM - priya Back To Top (25851)

 

how will you use delete query for the multivalued column.

Eg. Table "DETAILS" contains the columns such as "NAME", "Email-id"

Name   Email-id

aaa      [email protected],[email protected],[email protected]

QUERY : How will you delete [email protected] from the column Email-id????

NOTE : other value should not be deleted([email protected],[email protected])

please share it as soon as possible

 


Friday, July 12, 2013 - 12:47:06 PM - Brian Nordberg Back To Top (25818)

I've done the ForXML on huge datasets - billions of rows, with massive healthcare documents. It is amazingly fast. However watch out for Unicode values! XML can't handle them.


Friday, July 5, 2013 - 1:21:03 AM - Banwari Back To Top (25717)

 

Thanks for replying , 

It working well if it i have more values to show , but it's not workig for less data. 

3 [email protected]; [email protected] AND 45 other

4 [email protected] AND -1 other

On no:3 I am having 47 times [email protected] , so it is displaying well,

but on no :4 I have only one value and it is displaying  [email protected] AND -1 other  it meansa there are two values which is not right . It shold display only  [email protected] 


Thursday, July 4, 2013 - 11:07:17 AM - Douglas P. Castilho Back To Top (25713)

Hi Banwari,

I think this example will help you in your need

 

SELECT

   SS.SEC_NAME,

   STUFF((SELECT TOP 2 '; ' + US.USR_NAME 

          FROM USRS US

          WHERE US.SEC_ID = SS.SEC_ID

          FOR XML PATH('')), 1, 1, '') + ' AND ' + (SELECT CAST(COUNT(U.USR_NAME)-2 AS VARCHAR) + ' other'

                                                      FROM USRS U

                                                     WHERE U.SEC_ID = SS.SEC_ID) [SECTORS/USERS]

FROM SALES_SECTORS SS

GROUP BY SS.SEC_ID, SS.SEC_NAME

ORDER BY 1

 
I used "TOP 2" and this "2" value was subtracted in the "SELECT COUNT(...)" clause.
Try this example ok.
 
Have a nice day!
 

Thursday, July 4, 2013 - 10:22:56 AM - Banwari Back To Top (25712)

Thanks for sharing the great one.

I am trying to show only 3 value and for rest , I want to sum the number of values. For example

in below figure Entertainment contains values(Anderson. charles,Danny, lucas.) . So for this I want (Anderson,Charles and 2 other)

 Facebook notification is the best live example when you see any link it shows you Anderson,Joy and 20 other commented on  your post. Hope you get me

How can I get this result?


Thursday, May 30, 2013 - 10:04:52 AM - Nikheel Back To Top (25199)

Hi  Douglas,

This artical is one of the most important and healf full for every one.

It solved my problem in very effiecnt and optimised way.

great article.

Thanks,


Sunday, May 26, 2013 - 2:47:56 PM - David Back To Top (25146)

I hate it when people poo poo on things because it's not to their standard.

If someone came to you and asked for a one time extract of data in this format, are you going to turn them down and tell them they need to have a complete solution developed with all the different tiers to get the information they need?  No.

Yes, it may not be ideal, but not all of us work in an ideal world.  Sometimes people need data in a specific format now vs. later.  In a few minutes you could turn around and hand them the information they need vs. spending an hour explaining why you can't do something because it violates some standards that they're not familiar with or probably don't even care.


Saturday, May 25, 2013 - 8:56:59 AM - Javed Back To Top (25137)

 

 

Hi,

I agree with this example 

  thank's for clarify my doubt


Monday, May 6, 2013 - 1:39:37 PM - sunil kumar jain Back To Top (23741)

this is very nice example for manupulate muliple data (rows and coulmn) in a single.

 


Tuesday, April 30, 2013 - 5:21:50 PM - leon jhirad Back To Top (23641)

hi,

this is what looking for, i'ts a great, just quation how do i replace ";" with new line like chr(13).

 

can i do it ?

 

thanks

jhirad leon


Monday, April 15, 2013 - 12:44:40 PM - thomasD Back To Top (23357)

I could have used this about 3 months ago. :-) Instead I ended up with some complex TSQL. Thanks for the info, I'll certainly be using this in the future!


Saturday, April 6, 2013 - 7:10:58 PM - JustpassingBy Back To Top (23215)

Or 

you could just make a scalar valued function  AND call that as a Column

CREATE FUNCTION dbo.[getSectorUsersBySectorName]( @CurrentSectorName VARCHAR(30) )
RETURNS VARCHAR(MAX)
AS
BEGIN

       DECLARE @SectorUsers VARCHAR(MAX) = ''  

       
        SELECT @SectorUsers = @SectorUsers 

 + ISNULL(US.USR_NAME + '; ' , '')  

FROM SALES_SECTORS SS
INNER JOIN USRS US ON US.SEC_ID = SS.SEC_ID
         WHERE SS.SEC_NAME = @CurrentSectorName

-- @SectorUsers  wil hold A concetinated line with al users
        -- Return the result of the function

RETURN @SectorUsers
END

AND use it like so

SELECT distinct

   SS.SEC_NAME, 

   dbo.getSectorUsersBySectorName(SS.SEC_NAME) [SECTORS/USERS]

FROM SALES_SECTORS SS

ORDER BY 1 



 


Saturday, April 6, 2013 - 3:04:40 PM - Douglas Back To Top (23214)

Hi LadyRuna.

Cool, I'm glad it helped. I'll explore more alternatives for different needs that we always have.


Saturday, April 6, 2013 - 2:57:32 PM - Douglas Back To Top (23213)

Thank you Joe for the feedback and Greg for your reply. I used only simple T-SQL queries in examples.


Friday, April 5, 2013 - 5:23:52 PM - LadyRuna Back To Top (23198)

You posted this just in the nick of time. A moment ago, I had a coworker come up to me and ask how can he create t-SQL code to roll up multiple rows into a single row and column and all I had to do was send him the link to this tip.  :) 


Friday, April 5, 2013 - 3:09:26 PM - Greg Robidoux Back To Top (23195)

@Joe - thanks for the feedback and I agree this is more of a presentation aspect than SQL, but sometimes SSMS might be the one and only presentation layer there is.  I had the a recent need to roll-up information the same way and there was no front-end layer just T-SQL queries.


Friday, April 5, 2013 - 1:19:55 PM - Joe Celko Back To Top (23193)

Ever hear of First Normal Form (1NF)  and tiered architectures? You are violating both. This is done in a presentation layer in a correctly designed system. 















get free sql tips
agree to terms