Total sum wrong value in Dynamic Pivot - sql

I have complicated query which works pretty good (MS SQL 2012). But it makes a mistake when sum up same price items. It count them correctly but only takes price once instead of taking them as a count number. It only appears when same item has same price and from same country. Here is my query ;
CREATE TABLE #ITEMS(ID INT,NAME VARCHAR(30))
INSERT INTO #ITEMS
SELECT 1, 'laptop'
UNION ALL
SELECT 2, 'phone'
UNION ALL
SELECT 3, 'playstation'
UNION ALL
SELECT 4, 'MacBook'
CREATE TABLE #Country(ID INT,NAME VARCHAR(30))
INSERT INTO #Country
SELECT 1, 'England'
UNION ALL
SELECT 2, 'Sweden'
UNION ALL
SELECT 3, 'Russia'
UNION ALL
SELECT 4, 'Italy'
CREATE TABLE [#Pre-Request](Id INT, countryId INT, ItemId INT)
INSERT INTO [#Pre-Request]
SELECT 1,1,3
UNION ALL
SELECT 2,2,1
UNION ALL
SELECT 3,2,2
UNION ALL
SELECT 4,3,3
UNION ALL
SELECT 5,3,3
UNION ALL
SELECT 6,2,3
CREATE TABLE #Offers(Id INT, PRICE VARCHAR(50))
INSERT INTO #Offers
SELECT 18,'257$'
UNION ALL
SELECT 19,'151$'
UNION ALL
SELECT 20,'424$'
UNION ALL
SELECT 21,'433$'
UNION ALL
SELECT 22,'151$'
CREATE TABLE #Request(Id INT, preReqId INT, requestStatus INT,winOfferId INT)
INSERT INTO #Request
SELECT 44, 1, 3, 18
UNION ALL
SELECT 11, 2, 4, 21
UNION ALL
SELECT 53, 3, 4, 20
UNION ALL
SELECT 87, 4, 3, 22
UNION ALL
SELECT 43, 5, 3, 19
UNION ALL
SELECT 43, 6, 2, Null
;WITH CTE AS
(
SELECT DISTINCT I.NAME ITEMNAME,C.NAME COUNTRYNAME
,CAST(REPLACE(TAB.PRICE,'$','')AS INT)PRICE
,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN I.NAME END) OVER(PARTITION BY C.NAME,I.NAME) CNTITEM
FROM [#Pre-Request] PR
LEFT JOIN #Items I ON PR.ITEMID=I.ID
LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
OUTER APPLY
(
SELECT R.preReqId,R.winOfferId,O.PRICE
FROM #Request R
JOIN #Offers O ON R.winOfferId=O.Id
WHERE PR.ID=R.preReqId
)TAB
UNION
-- Used to select Item name and country that are not in Pre-request table and other tables
SELECT I.NAME ,C.NAME ,NULL,0
FROM #Items I
CROSS JOIN #COUNTRY C
)
,CTE2 AS
(
-- Find the sum for number of items
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME,
SUM(PRICE)PRICE
FROM CTE
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
,CTE3 AS
(
-- Find the sum of PRICE
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME--,CNTITEM
,SUM(CNTITEM)CNTITEM
FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,CNTITEM
FROM CTE
)TAB
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
SELECT C2.*,C3.CNTITEM,
CAST(C3.CNTITEM AS VARCHAR(20))+'x'+' ' + CAST(C2.PRICE AS VARCHAR(20))+'$' NEWCOL
INTO #NEWTABLE
FROM CTE2 C2
JOIN CTE3 C3 ON C2.COUNTRYNAME=C3.COUNTRYNAME AND C2.ITEMNAME=C3.ITEMNAME
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + ITEMNAME + ']', '[' + ITEMNAME + ']')
FROM (SELECT DISTINCT ITEMNAME FROM #NEWTABLE WHERE ITEMNAME<>'TOTAL') PV
ORDER BY ITEMNAME
-- Since we need Total in last column, we append it at last
SELECT #cols += ',[Total]'
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT COUNTRYNAME,' + #cols + ' FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,ISNULL(NEWCOL,''0x 0$'')NEWCOL
FROM #NEWTABLE
) x
PIVOT
(
MIN(NEWCOL)
FOR ITEMNAME IN (' + #cols + ')
) p
ORDER BY CASE WHEN (COUNTRYNAME=''Total'') THEN 1 ELSE 0 END,COUNTRYNAME'
EXEC SP_EXECUTESQL #query
and here is result ;
As you can see there are 2 "playstation" from "Russia" it takes correct count (2x) but only take 1 price "151$" (normally it must be 302$). How can I fix this without making major changes from query? Thank you.

I think this does what you want. The problem is in your first CTE where you do the item count and get a distinct on the ItemName, CountryName, and Price.
Instead of getting a distinct, do a group by as shown below and SUM the price.
SELECT I.NAME ITEMNAME, C.NAME COUNTRYNAME
,SUM(CAST(REPLACE(TAB.PRICE,'$','')AS INT))PRICE
,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN 1 ELSE NULL END) CNTITEM
FROM [#Pre-Request] PR
LEFT JOIN #Items I ON PR.ITEMID=I.ID
LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
OUTER APPLY
(
SELECT R.preReqId,R.winOfferId,O.PRICE
FROM #Request R
JOIN #Offers O ON R.winOfferId=O.Id
WHERE PR.ID=R.preReqId
)TAB
GROUP BY
I.NAME
,C.NAME
EDIT:
Here are the results I get:
Here's all of your code starting from the CTEs:
;WITH CTE AS
(
SELECT I.NAME ITEMNAME, C.NAME COUNTRYNAME
,SUM(CAST(REPLACE(TAB.PRICE,'$','')AS INT))PRICE
,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN 1 ELSE NULL END) CNTITEM
FROM [#Pre-Request] PR
LEFT JOIN #Items I ON PR.ITEMID=I.ID
LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
OUTER APPLY
(
SELECT R.preReqId,R.winOfferId,O.PRICE
FROM #Request R
JOIN #Offers O ON R.winOfferId=O.Id
WHERE PR.ID=R.preReqId
)TAB
GROUP BY
I.NAME
,C.NAME
UNION
-- Used to select Item name and country that are not in Pre-request table and other tables
SELECT I.NAME ,C.NAME ,NULL,0
FROM #Items I
CROSS JOIN #COUNTRY C
)
,CTE2 AS
(
-- Find the sum for number of items
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME,
SUM(PRICE)PRICE
FROM CTE
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
,CTE3 AS
(
-- Find the sum of PRICE
SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME--,CNTITEM
,SUM(CNTITEM)CNTITEM
FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,CNTITEM
FROM CTE
)TAB
GROUP BY ITEMNAME,COUNTRYNAME
WITH CUBE
)
SELECT C2.*,C3.CNTITEM,
CAST(C3.CNTITEM AS VARCHAR(20))+'x'+' ' + CAST(C2.PRICE AS VARCHAR(20))+'$' NEWCOL
INTO #NEWTABLE
FROM CTE2 C2
JOIN CTE3 C3 ON C2.COUNTRYNAME=C3.COUNTRYNAME AND C2.ITEMNAME=C3.ITEMNAME
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + ITEMNAME + ']', '[' + ITEMNAME + ']')
FROM (SELECT DISTINCT ITEMNAME FROM #NEWTABLE WHERE ITEMNAME<>'TOTAL') PV
ORDER BY ITEMNAME
-- Since we need Total in last column, we append it at last
SELECT #cols += ',[Total]'
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT COUNTRYNAME,' + #cols + ' FROM
(
SELECT DISTINCT ITEMNAME,COUNTRYNAME,ISNULL(NEWCOL,''0x 0$'')NEWCOL
FROM #NEWTABLE
) x
PIVOT
(
MIN(NEWCOL)
FOR ITEMNAME IN (' + #cols + ')
) p
ORDER BY CASE WHEN (COUNTRYNAME=''Total'') THEN 1 ELSE 0 END,COUNTRYNAME'
EXEC SP_EXECUTESQL #query

Related

converting rows to columns dynamicaly based on conditions

In the below image I have current data and expected data based on the first three columns the data need to get transpose
Table query:
drop table ##Test
CREATE TABLE ##Test
(paymentid varchar(30),
claimid bigint,
Lineno1 int,
groupcode varchar(2),
Carc int,
adjustmentamt float,
RARC varchar(30),
Edit1 varchar(30),
Remit varchar(30),
)
INSERT INTO ##Test
(paymentid ,
claimid ,
Lineno1 ,
groupcode ,
Carc ,
adjustmentamt ,
RARC ,
Edit1 ,
Remit )
VALUES
('QP18502291',14205893514,2,'CO',84,75.55,'N20','','D18')
('QP15930339',14127612308,1,'OA',23,263,'','ClaimDetail.COBAmt','') ,
('QP15930339',14127612308,1,'OA',23,21.69,'','ClaimDetail.COBAmt',''),
('QP18502291',14205893514,2,'OA',23,78.77,'','ClaimDetail.COBAmt',''),
('QP18502291',14205893514,2,'OA',97,66.55,'N20','','D18')
select * from ##Test
Possible duplicate post and take a look at the solution.
See SQL Fiddle with Demo.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(col+cast(rn as varchar(10)))
from
(
select row_number() over(partition by paymentid order by Lineno1) rn
from ##Test
) d
cross apply
(
select 'groupcode', 1 union all
select 'carc', 2 union all
select 'adjustmentamt', 3 UNION ALL
SELECT 'rarc',4 UNION ALL
SELECT 'Edit1' ,5 UNION ALL
SELECT 'remit',6
) c (col, so)
group by col, rn, so
order by rn, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT paymentid, claimid,Lineno1,' + #cols + '
from
(
select paymentid, claimid,Lineno1, col+cast(rn as varchar(10)) col, value
from
(
select paymentid, claimid,Lineno1, groupcode, carc, adjustmentamt,rarc,Edit1,remit,
row_number() over(partition by paymentid order by Lineno1) rn
from ##Test
) t
cross apply
(
select ''groupcode'', groupcode union all
select ''carc'', cast(carc as varchar(50)) union all
select ''adjustmentamt'', cast(adjustmentamt as varchar(50)) union all
select ''rarc'', rarc union all
select ''Edit1'' , Edit1 union all
select ''remit'' , remit
) c (col, value)
) x pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute(#query)

How to merge column this specific way in SQL

My original table is this;
TableName= NewRetail
CustomerID 1 2 3 4 5 6 7.....30
1 30 31 Null Null Null Null Null
2 24 78 35 72 Null Null Null
I want to store this table in 'Retail'
CustomerId Itemset
1 30
1 31
2 24
2 78
2 35
2 72
There are no duplicates in any row in Original(Source) Table.
Thanks. I tried using Loops but couldn't make it work. Been stuck at it since three days.
You can use table valued constructor with Cross apply to unpivot the data
SELECT CustomerID,
Itemset
FROM Yourtable
CROSS apply (VALUES ([1]),([2]),([3]),([4]),([5]),([6]),([7]),...) cs (Itemset)
WHERE Itemset IS NOT NULL
Dynamic Version
DECLARE #itemset VARCHAR(max)='',
#sql NVARCHAR(max);
WITH cte
AS (SELECT TOP 30 Row_number()OVER(ORDER BY (SELECT NULL)) RN
FROM sys.columns)
SELECT #itemset += '(' + Quotename(RN) + '),'
FROM cte
SET #itemset = LEFT(#itemset, Len(#itemset) - 1)
SET #sql = 'SELECT CustomerID,
Itemset
FROM Yourtable
CROSS apply (VALUES ' + #itemset
+ ') cs (Itemset)
WHERE Itemset IS NOT NULL '
EXEC Sp_executesql #sql
You can do this using UNION ALL:
SELECT *
FROM (
SELECT CustomerId, [1] AS ItemSet FROM NewRetail UNION ALL
SELECT CustomerId, [2] FROM NewRetail UNION ALL
SELECT CustomerId, [3] FROM NewRetail UNION ALL
SELECT CustomerId, [4] FROM NewRetail UNION ALL
SELECT CustomerId, [5] FROM NewRetail UNION ALL
SELECT CustomerId, [6] FROM NewRetail UNION ALL
SELECT CustomerId, [7] FROM NewRetail UNION ALL
...
SELECT CustomerId, [30] FROM NewRetail
)t
WHERE ItemSet IS NOT NULL
ORDER BY CustomerId
Using dynamic SQL:
;WITH Tally(N) AS(
SELECT TOP 30 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM sys.columns
)
SELECT #sql = #sql +
CASE
WHEN #sql = '' THEN 'SELECT CustomerId, [' + CONVERT(VARCHAR(2), N) + '] AS ItemSet FROM NewRetail'
ELSE ' UNION ALL' + CHAR(10) +' SELECT CustomerId, [' + CONVERT(VARCHAR(2), N) + '] FROM NewRetail'
END
FROM Tally
SELECT #sql =
'SELECT *
FROM (
' + #sql + CHAR(10) +
')t
WHERE ItemSet IS NOT NULL
ORDER BY CustomerId'
PRINT #sql
EXEC (#sql)
It is a simple UNPIVOT operation. NULLs automatically eliminated from result:
declare #t table(custid int, [1] int, [2] int, [3] int)
insert into #t values
(1, 10, 30, null),
(2, 30, 40, 50)
select custid, c from #t
unpivot(c for p in([1], [2], [3])) p
Fiddle http://sqlfiddle.com/#!6/9eecb/1733

SQL multiple replace

I want to read the company table and take out all possible suffixes from the name. Here's what I have so far:
declare #badStrings table (item varchar(50))
INSERT INTO #badStrings(item)
SELECT 'company' UNION ALL
SELECT 'co.' UNION ALL
SELECT 'incorporated' UNION ALL
SELECT 'inc.' UNION ALL
SELECT 'llc' UNION ALL
SELECT 'llp' UNION ALL
SELECT 'ltd'
select id, (companyname = Replace(name, item, '') FROM #badStrings)
from companies
where name != ''
Ed Northridge's answer will work, and I have upvoted it, but just in case multiple replacements are required I am adding another option using his sample data. If, for example one of the companies was called "The PC Company LTD" This would duplicate rows in the output with one being "The PC LTD" and the other "The PC Company". To resolve this there are 2 option depending on your desired outcome. The first is to only replace the "Bad Strings" when they occur at the end of the name.
SELECT c.ID, RTRIM(x.Name) [Name]
FROM #companies c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
-- WHERE CLAUSE ADDED HERE
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND x.[Name] != c.Name
This would yield "The PC Company" with no duplicates.
The other option is replace All occurances of the Bad Strings recursively:
;WITH CTE AS
( SELECT c.ID, c.Name [OriginalName], RTRIM(x.Name) [Name], 1 [Level]
FROM #companies c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND RTRIM(x.Name) != c.Name
UNION ALL
SELECT c.ID, OriginalName, RTRIM(x.Name) [Name], Level + 1 [Level]
FROM CTE c
OUTER APPLY
( SELECT REPLACE(c.name, item, '') AS [Name]
FROM #badStrings
WHERE CHARINDEX(item, c.Name) = 1 + LEN(c.Name) - LEN(Item)
) x
WHERE c.name != ''
AND x.[Name] != c.Name
)
SELECT DISTINCT ID, Name, OriginalName
FROM ( SELECT *, MAX(Level) OVER(PARTITION BY ID) [MaxLevel]
FROM CTE
) c
WHERE Level = maxLevel
This would yield "The PC" from "The PC Company".
The error I got running the snippet was:
Msg 102, Level 15, State 1, Line 12
Incorrect syntax near '='.
The below code isn't an ideal solution - it will only return a list of companies where their name has been changed by the REPLACE function.
declare #companies table (id int, name nvarchar(50))
INSERT INTO #companies(id, name)
SELECT 1,'One Company' UNION ALL
SELECT 2, 'Two co.' UNION ALL
SELECT 3, 'Three incorporated' UNION ALL
SELECT 4, 'Four inc.' UNION ALL
SELECT 5, 'Five llc' UNION ALL
SELECT 6, 'Six llp' UNION ALL
SELECT 7, 'Seven ltd'
select * from #companies
declare #badStrings table (item varchar(50))
INSERT INTO #badStrings(item)
SELECT 'company' UNION ALL
SELECT 'co.' UNION ALL
SELECT 'incorporated' UNION ALL
SELECT 'inc.' UNION ALL
SELECT 'llc' UNION ALL
SELECT 'llp' UNION ALL
SELECT 'ltd'
select * from #badStrings
Here is the edited query:
select id, x.Name
from #companies c
OUTER APPLY (
SELECT Replace(c.name, item, '') AS [Name]
FROM #badStrings
) x
where c.name != ''
AND x.[Name] != c.Name
This returns:
id Name
----------- --------
1 One
2 Two
3 Three
4 Four
5 Five
6 Six
7 Seven
(7 row(s) affected)
Hopefully it's useful
Edit:
An alternative to apply the match to those company names which end with the #badStrings value
select id, x.Name
from #companies c
OUTER APPLY (
SELECT Replace(c.name, item, '') AS [Name]
FROM #badStrings
WHERE c.Name LIKE '%'+item
) x
where c.name != ''

How to declare the columns dynamically in a Select query using PIVOT

I am writing a query to get the address for PersonID. Following query is working for me but it only returns with two Addresses. I want to handle the 'n' number of address with a single query. Is there any way to do this?
Many thanks
SELECT
PersonID, PersonName
[Address1], [Address2]
FROM
(
SELECT
P.PersonID,
P.PersonName,
(ROW_NUMBER() OVER(PARTITION BY P.PersonID ORDER BY A.AddressID)) RowID
FROM tblPerson
INNER JOIN tblAddress AS A ON A.PersonID = P.PersonID
) AS AddressTable
PIVOT
(
MAX(AddressID)
FOR RowID IN ([Address1], [Address2])
) AS PivotTable;
Assuming the following tables and sample data:
USE tempdb;
GO
CREATE TABLE dbo.tblPerson(PersonID INT, PersonName VARCHAR(255));
INSERT dbo.tblPerson SELECT 1, 'Bob'
UNION ALL SELECT 2, 'Charlie'
UNION ALL SELECT 3, 'Frank'
UNION ALL SELECT 4, 'Amore';
CREATE TABLE dbo.tblAddress(AddressID INT, PersonID INT, [Address] VARCHAR(255));
INSERT dbo.tblAddress SELECT 1,1,'255 1st Street'
UNION ALL SELECT 2,2,'99 Elm Street'
UNION ALL SELECT 3,2,'67 Poplar Street'
UNION ALL SELECT 4,2,'222 Oak Ave.'
UNION ALL SELECT 5,1,'36 Main Street, Suite 22'
UNION ALL SELECT 6,4,'77 Sicamore Ct.';
The following query gets the results you want, and shows how it handles 0, 1 or n addresses. In this case the highest number is 3 but you can play with more addresses if you like by adjusting the sample data slightly.
DECLARE #col NVARCHAR(MAX) = N'',
#sel NVARCHAR(MAX) = N'',
#from NVARCHAR(MAX) = N'',
#query NVARCHAR(MAX) = N'';
;WITH m(c) AS
(
SELECT TOP 1 c = COUNT(*)
FROM dbo.tblAddress
GROUP BY PersonID
ORDER BY c DESC
)
SELECT #col = #col + ',[Address' + RTRIM(n.n) + ']',
#sel = #sel + ',' + CHAR(13) + CHAR(10) + '[Address' + RTRIM(n.n) + '] = x'
+ RTRIM(n.n) + '.Address',
#from = #from + CHAR(13) + CHAR(10) + ' LEFT OUTER JOIN xMaster AS x'
+ RTRIM(n.n) + ' ON x' + RTRIM(n.n) + '.PersonID = p.PersonID AND x'
+ RTRIM(n.n) + '.rn = ' + RTRIM(n.n)
FROM m CROSS JOIN (SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_columns) AS n WHERE n.n <= m.c;
SET #query = N';WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName' + #col
+ ' FROM
(
SELECT p.PersonID, p.PersonName, ' + STUFF(#sel, 1, 1, '')
+ CHAR(13) + CHAR(10) + ' FROM dbo.tblPerson AS p ' + #from + '
) AS Addresses;';
PRINT #query;
--EXEC sp_executesql #query;
If you print the SQL you will see this result:
;WITH xMaster AS
(
SELECT PersonID, Address,
rn = ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Address)
FROM dbo.tblAddress
)
SELECT PersonID, PersonName,[Address1],[Address2],[Address3] FROM
(
SELECT p.PersonID, p.PersonName,
[Address1] = x1.Address,
[Address2] = x2.Address,
[Address3] = x3.Address
FROM dbo.tblPerson AS p
LEFT OUTER JOIN xMaster AS x1 ON x1.PersonID = p.PersonID AND x1.rn = 1
LEFT OUTER JOIN xMaster AS x2 ON x2.PersonID = p.PersonID AND x2.rn = 2
LEFT OUTER JOIN xMaster AS x3 ON x3.PersonID = p.PersonID AND x3.rn = 3
) AS Addresses;
If you execute it, you will see this:
I know the query to get here is an ugly mess, but your requirement dictates it. It would be easier to return a comma-separated list as I suggested in my comment, or to have the presentation tier deal with the pivoting.

SQL query problem

Let´s say I have two tables, "Garden" and "Flowers". There is a 1:n-relationship between these tables, because in a garden can be many flowers. Is it possible to write an SQL query which returns a result with the following structure:
GardenName Flower1Name Flower2Name .... (as long as there are entries in flowers)
myGarden rose tulip
CREATE TABLE #Garden (Id INT, Name VARCHAR(20))
INSERT INTO #Garden
SELECT 1, 'myGarden' UNION ALL
SELECT 2, 'yourGarden'
CREATE TABLE #Flowers (GardenId INT, Flower VARCHAR(20))
INSERT INTO #Flowers
SELECT 1, 'rose' UNION ALL
SELECT 1, 'tulip' UNION ALL
SELECT 2, 'thistle'
DECLARE #ColList nvarchar(max)
SELECT #ColList = ISNULL(#ColList + ',','') + QUOTENAME('Flower' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS VARCHAR))
FROM #Flowers WHERE GardenId = (
SELECT TOP 1 GardenId
FROM #Flowers
ORDER BY COUNT(*) OVER (PARTITION BY GardenId) DESC
)
EXEC (N'
;WITH cte As
(
SELECT *, ''Flower'' + CAST(ROW_NUMBER() OVER (PARTITION BY GardenId ORDER BY (SELECT 0)) AS VARCHAR) RN
FROM #Flowers F
)
SELECT Name,' + #ColList + N'
FROM cte
JOIN #Garden g ON g.Id = GardenId
PIVOT (MAX(Flower) FOR RN IN (' + #ColList + N')) Pvt')
DROP TABLE #Garden
DROP TABLE #Flowers
Returns
Name Flower1 Flower2
-------------------- -------------------- --------------------
myGarden rose tulip
yourGarden thistle NULL
Look at using Pivot in SQL Server. Here is a good link that goes over how it works:
http://www.kodyaz.com/articles/t-sql-pivot-tables-in-sql-server-tutorial-with-examples.aspx
Ok, i think i got it working. Try this:
with temp as
(
select 'myGarden' as name, 'test1' as flower
union
select 'myGarden','test2'
union
select 'myGarden','test5'
union
select 'abeGarden','test4'
union
select 'abeGarden','test5'
union
select 'martinGarden', 'test2'
)
select* from temp
pivot
(
max(flower)
for flower in (test1,test2,test3,test4,test5)
) PivotTable
You could also make the values in the in clause dynamic. Since this is a CTE i can't in my example.
Dynamic SQL with a cursor is the only way I can think of, and it won't be pretty.
If you only want the results for one garden at a time this would give you the data:
select gardenName from tblGarden where gardenid = 1
Union ALL
select tblFLowers.flowerName from tblFlowers where gardenid = 1