SQL Server 2005 pivot table - sql

I want to pivot a column in SQL Server 2005. I'm pretty sure there is XML way to get it done but can't figure it out. Here is a table:
ID Class
1 20002
1 20003
1 20004
2 20003
2 20012
Desired value is:
ID Class
1 20002,20003,20004
2 20003,20012
Thanks in advance

I am not sure PIVOT (or UNPIVOT) are what you are looking for. Below is some code that I use when I need to get a CSV list embedded in a query. Hope it helps!
SELECT DISTINCT
ID
, Class = STUFF(
cast(
(select ', ' + cast(Class as nvarchar)
from TableName t2
WHERE t2.ID = t1.ID
for xml path('')) as nvarchar(2000))
,1,2, N'')
FROM TableName t1

Related

Stuff Function in SQL Server - Dealing with Several Primary Keys [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
SQL group_concat function in SQL Server
I am looking to create a query but somehow I am unable to do so. Can anyone please help me out here?
The original data
ID ReportId Email
1 1 a#a.com
2 2 b#b.com
3 1 c#c.com
4 3 d#d.com
5 3 e#e.com
I want to group by ReportId, but all the email should be comma separated. So the result should be:
ReportId Email
1 a#a.com, c#c.com
2 b#b.com
3 d#d.com, e#e.com
What is the best way to do this?
I am trying the group by clause but if there is any other thing then i am open to implement that also. I really appreciate your time and help on this. Thank you.
try this:
SELECT ReportId, Email =
STUFF((SELECT ', ' + Email
FROM your_table b
WHERE b.ReportId = a.ReportId
FOR XML PATH('')), 1, 2, '')
FROM your_table a
GROUP BY ReportId
SQL fiddle demo
SELECT [ReportId],
SUBSTRING(d.EmailList,1, LEN(d.EmailList) - 1) EmailList
FROM
(
SELECT DISTINCT [ReportId]
FROM Table1
) a
CROSS APPLY
(
SELECT [Email] + ', '
FROM Table1 AS B
WHERE A.[ReportId] = B.[ReportId]
FOR XML PATH('')
) D (EmailList)
SQLFiddle Demo

SQL Server: Select multiple records in one select statement

In a query like this one:
SELECT *
FROM `Order`
WHERE `CustID` = '1'
My results are displayed like so:
| CustID| Order |
-----------------
| 1 | Order1|
| 1 | Order2|
| 1 | Order3|
-----------------
How do I write SQL statement, to get a result like this one?:
| CustID| Order |
---------------------------------
| 1 | Order1, Order2, Order3|
---------------------------------
In mySQL it's possible with Group_Concat, but in SQL Server it gives error like syntax error or some.
Use xml path (see fiddle)
SELECT distinct custid, STUFF((SELECT ',' +[order]
FROM table1 where custid = t.custid
FOR XML PATH('')), 1, 1, '')
FROM table1 t
where t.custid = 1
STUFF replaces the first , with an empty string, i.e. removes it. You need a distinct otherwise it'll have a match for all orders since the where is on custid.
FOR XML
PATH Mode
STUFF
You can use Stuff function and For xml clause like this:
SELECT DISTINCT CustId, STUFF((
SELECT ','+ [Order]
FROM [Order] T2
WHERE T2.CustId = T1.CustId
FOR XML PATH('')
), 1, 1, '')
FROM [Order] T1
fiddle here
Note: Using order as a table name or a column name is a very, very bad idea. There is a reason why they called reserved words reserved.
See this link for my favorite way to avoid such things.
try this.
Change table name and column names for what you need;
SELECT custID,
LISTAGG(Order, ', ') WITHIN GROUP (ORDER BY Order) text
FROM table_name
GROUP BY custID
edit for MSSQL . You should use group_concat function.
SELECT custID, GROUP_CONCAT(Order)
FROM table_name
WHERE CustID = 1
GROUP BY custID;

Combining Data From Multiple Rows

I have 3 tables I am writing a query for: Memos, Memos_Description, Policies. The database was not designed by myself and I cannot change it, this is simply a report.
I currently have a query that seems to be working, but is extremely inefficient before joining the extra tables that I need.
SELECT
Main.CLIENTSNAME,
Main.ENTRYDATE,
Main.AUTHOR,
Main.POLICYNUMBER,
Main.CLIENTS_ID,
Main.MEMOS_ID,
Left(Main.DESCRIPTION,Len(Main.DESCRIPTION)) AS REGARDING
FROM
(
SELECT distinct ST1.MEMOS_ID,
(
SELECT ST2.DESCRIPTION + ' ' AS [text()]
FROM dbo.MEMOS_DESCRIPTION ST2
WHERE ST1.MEMOS_ID = ST2.MEMOS_ID
ORDER BY ST1.MEMOS_ID
For XML PATH ('')
) [DESCRIPTION],
ST1.CLIENTSNAME,
ST1.ENTRYDATE,
ST1.AUTHOR,
ST1.POLICYNUMBER,
ST1.REGARDING,
ST1.CLIENTS_ID
FROM dbo.MEMOS ST1
) [Main]
The tables look like this:
tbl.MEMOS
MEMOS_ID
POLICIES_ID
CLIENTSNAME
tbl.MEMOS_DESCRIPTION
MEMOS_ID
DESCRIPTION
tbl.POLICIES
POLICIES_ID
POLICYNUMBER
The data looks like this:
tbl1.MEMOS_ID | tbl1.CLIENTSNAME
1 PERSON ONE
2 PERSON TWO
3 PERSON THREE
tbl2.MEMOS_ID | tbl2.DESCRIPTION
1 This is a sentence
1 that can run over more
1 than one description record.
2 Person two has
2 something different.
3 Client Created.
tbl3.POLICIES_ID | tbl3.POLICYNUMBER
123 ABCDE
456 FGHIJ
I would like the report to look like:
tbl1.MEMOS_ID | tbl1.CLIENTSNAME | tbl2.DESCRIPTION | tbl3.POLICIES_ID | tbl3.POLICYNUMBER
1 PERSON ONE This is a sentence that can run over more tan one description record. 123 ABCDE
I hope this makes sense and thank you.
Updated Query as per Gordon's suggested answer:
SELECT ST1.*,
STUFF(
(SELECT ' ' + ST2.DESCRIPTION AS [text()]
FROM dbo.MEMOS_DESCRIPTION ST2
WHERE ST1.MEMOS_ID = ST2.MEMOS_ID
ORDER BY ST1.MEMOS_ID
For XML PATH ('')
), 1, 1, '') [REGARDING]
FROM
(SELECT DISTINCT ST1.MEMOS_ID,
ST1.CLIENTSNAME,
ST1.ENTRYDATE,
ST1.AUTHOR,
ST1.POLICYNUMBER,
ST1.CLIENTS_ID,
ST1.POLICIES_ID
FROM dbo.MEMOS ST1
) ST1
LEFT JOIN POLICIES B
ON ST1.POLICIES_ID = B.POLICIES_ID
WHERE ST1.ENTRYDATE >= DATEADD(month, -2, GETDATE())
AND (B.PROD1 = ('123') OR B.PROD1 = ('456') OR B.PROD1 = ('789'))
How does the performance compare if you do the select distinct before doing the string aggregation?
SELECT ST1.*,
STUFF((SELECT ' ' + ST2.DESCRIPTION AS [text()]
FROM dbo.MEMOS_DESCRIPTION ST2
WHERE ST1.MEMOS_ID = ST2.MEMOS_ID
ORDER BY ST1.MEMOS_ID
For XML PATH ('')
), 1, 1, '') ) [DESCRIPTION]
FROM (SELECT DISTINCT T1.MEMOS_ID, ST1.CLIENTSNAME, ST1.ENTRYDATE,
ST1.AUTHOR, ST1.POLICYNUMBER, ST1.REGARDING, ST1.CLIENTS_ID
FROM dbo.MEMOS ST1
) ST1
I suspect that SQL Server might be doing the string aggregation for every row before running distinct -- and that is a lot of unnecessary work.

SQL Group column data from joins

I need some help with writing SQL query.
I've data in the following format coming from a query returned by joining multiple tables.
CustID Name AccNo Bank
------ ---- ----- -----
1 Varun 9848032919 CB
1 Varun 9998887771 COB
1 Varun 9988776655 CB
2 Lokesh 9876543210 COB
2 Lokesh 9282726252 CB
3 aaaa 9181716151 COB
I would like the data to be formatted as below so that it would be easy to load into Crystal reports.
CustID Name AccNo Bank
------ ---- ----- -----
1 Varun 9848032919,9998887771,9988776655 CB,COB,CB
2 Lokesh 9876543210,9282726252 COB,CB
3 aaaa 9181716151 COB
I've looked at other answers which suggest using STUFF, XML PATH() but they are applicable only if data comes from one table. In my scenario data is retrieved by joining multiple tables.
May I know how to group by CustID and concatenate data in other columns as I desire?
Thanks a lot for your time!!!
EDIT: I'm looking for a SQL Server 2005 version answer
You can place the query inside a CTE, then apply FOR XML PATH on this CTE like this:
;WITH CTE AS (
... your query here
)
SELECT C.CustID, MAX(Name),
STUFF((
SELECT ', ' + + CAST(AccNo AS VARCHAR(MAX))
FROM CTE
WHERE (CustID = C.CustID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS AccNo,
STUFF((
SELECT ', ' + + CAST(Bank AS VARCHAR(MAX))
FROM CTE
WHERE (CustID = C.CustID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS Bank
FROM CTE C
GROUP BY C.CustID
Wrapping the select makes it look like a simple table. You can apply the logic on the result.
Like
Select a.*
from (select t1.col1, t2.col2
from table1 t1
join table2 t2 on t1.f1=t2.c1) a

How to join all data in table for one column as string with sql?

I want to join all data in table. For example: I have a table like this,
ID Name ForeingId
----------------------
1 A 1
2 B 1
3 C 2
4 D 1
5 E 1
I want to get as a result the following with query. Such as 'SELECT ... WHERE ForeingId=1' .
I dont want to use procedure or function.
result : A,B,D,E
For ORACLE, try this:
SELECT
LISTAGG(name, ',') WITHIN GROUP (ORDER BY name) AS NAME
FROM TABLE
WHERE ForeingId= '1'
I am using MSSQL
I thank everyone for the answers. I found answer with link of #mehul9595's comment.
Simulating group_concat MySQL function in Microsoft SQL Server 2005?
This way:
SELECT STUFF(
(SELECT ',' + t.name FROM table_name t
where t.foreingId = 1 FOR XML PATH ('')), 1, 1, '')