Reputation: 11
Alright, I'll try to explain this as simple a possible.
I have a table called approval_levels in which I have 2 columns:
|LEVEL_ID |NAME |
|1 |app_level_1 |
|2 |app_level_2 |
|3 |app_level_3 |
I have a second table called requests, in which I have 3 columns:
|REQUEST_ID |PRODUCT_NAME |MANUFACTURER |
|1 |wd-40 |Acme |
|2 |Windex |Acme |
|3 |Propane |Acme |
I have a third table which links the two called request_approvals which has 2 columns: REQUEST_ID, LEVEL_ID. When a request is approved for a specific level, I insert a value into this table. So, for example, lets say request 1 has been approved for all 3 levels, request 2 has been approved for only level 1, and request 3 has been approved for level 3, the table would show something like this.
|REQUEST_ID |LEVEL_ID |
|1 |1 |
|1 |2 |
|1 |3 |
|2 |1 |
|3 |3 |
Ok, so here the challenge: I need to show in a report all the requests, create a columns for each level and show whether or not that request is approved for that level. The end result has to be something like this:
|REQUEST_ID |PRODUCT_NAME |MANUFACTURER |app_level_1 |app_level_2 |app_level_3 |
|1 |wd-40 |Acme |X |X |X |
|2 |Windex |Acme |X | | |
|3 |Propane |Acme | | |X |
Keep in mind that if another value is added to the approval_levels table (ie app_level_4), I need to add another column to the table call app_level_4 dynamically.
Now, how in the world do I do something like this??? I don't even know where to start looking?
Thanks for the help!
Upvotes: 1
Views: 1718
Reputation: 747
there is sql server tag in here, so you can try below query i use the data example that u provided (probably the field name is different, and check the table name)
with Pivot:
-- pivot solution
select pvt.request_id, pvt.product_name, pvt.manufacturer
--pivot columns
, case when pvt.[1] = 1 then 'X' else '' end as lvl1
, case when pvt.[2] = 1 then 'X' else '' end as lvl2
, case when pvt.[3] = 1 then 'X' else '' end as lvl3
--, case when pvt.[4] = 1 then 'X' else '' end as lvl4
from
(
select a.request_id, a.product_name, a.manufacturer, b.level_id
from @requests a
left join @request_approval b on a.request_id=b.request_id
) aa
Pivot
(
count(aa.level_id)
for aa.level_id in([1],[2],[3] /*,[4]*/)
) as pvt
with Join (left join):
select tbl.request_id,tbl.product_name,tbl.manufacturer
, case when zz.applvl1 is not null then 'X' else '' end as lvl1
, case when xx.applvl2 is not null then 'X' else '' end as lvl2
, case when yy.applvl3 is not null then 'X' else '' end as lvl3
from
@requests tbl left join
(
select a.request_id, a.product_name, a.manufacturer, cc.Name as applvl1
from @requests a
left join @request_approval b on a.request_id=b.request_id
left join (select c.level_ID, c.name from @Approval_levels c where c.level_ID = 1) cc on b.level_id=cc.level_ID
where b.level_id = 1
) as zz on tbl.request_id = zz.request_id
left join
(
select a.request_id, a.product_name, a.manufacturer, dd.Name as applvl2
from @requests a
left join @request_approval b on a.request_id=b.request_id
left join (select c.level_ID, c.name from @Approval_levels c where c.level_ID = 2) dd on b.level_id=dd.level_ID
where b.level_id = 2
) as xx on tbl.request_id=xx.request_id
left join
(
select a.request_id, a.product_name, a.manufacturer, ee.Name as applvl3
from @requests a
left join @request_approval b on a.request_id=b.request_id
left join (select c.level_ID, c.name from @Approval_levels c where c.level_ID = 3) ee on b.level_id=ee.level_ID
where b.level_id = 3
) as yy on tbl.request_id=yy.request_id
--FOR the next Level
/*
left join
(
select a.request_id, a.product_name, a.manufacturer, ee.Name as applvl4
from @requests a
left join @request_approval b on a.request_id=b.request_id
left join (select c.level_ID, c.name from @Approval_levels c where c.level_ID = 3) ff on b.level_id=ff.level_ID
where b.level_id = 4
) as ww on tbl.request_id=ww.request_id
--don't forget to add ww.applv4 in the select column
*/
RESULT:
-- LEFT JOIN RESULT
request_id product_name manufacturer lvl1 lvl2 lvl3
----------- ------------- ------------- ---- ---- ----
1 wd-40 Acme X X X
2 Windex Acme X
3 Propane Acme X
-- PIVOT RESULT
request_id product_name manufacturer lvl1 lvl2 lvl3
----------- ------------ -------------- --------------
1 wd-40 Acme X X X
2 Windex Acme X
3 Propane Acme X
Upvotes: 0
Reputation:
If you're using SQL Server, take a look at the PIVOT command. I just wrote one of these myself, so I modified it to fit your table structure:
DECLARE @COLUMNS NVARCHAR(MAX)
DECLARE @SQL NVARCHAR(MAX)
SELECT @COLUMNS = COALESCE(@COLUMNS + ', ','') + QUOTENAME(NAME) FROM approval_levels
SELECT @SQL = N'
SELECT REQUEST_ID, PRODUCT_NAME, MANUFACTURER, ' + @COLUMNS + '
FROM (
SELECT
r.REQUEST_ID,
r.PRODUCT_NAME,
r.MANUFACTURER,
a.NAME
FROM
request_approvals ra
INNER JOIN approval_levels a ON a.LEVEL_ID = ra.LEVEL_ID
INNER JOIN requests r ON r.REQUEST_ID = ra.REQUEST_ID
) p
PIVOT(COUNT(NAME) FOR NAME IN ( ' + @COLUMNS + ' )
) AS pvt'
EXEC sp_executesql @SQL
Upvotes: 3
Reputation: 482
As Phillip said the best way would be a pivot table.
you can select the columns for the pivot table by doing something like so
SELECT DISTINCT NAME INTO #TEMP
FROM approval_levels
DECLARE @cols NVARCHAR(2000)
SET @cols = STUFF(( SELECT "],[" + t.NAME
FROM #Temp AS t
FOR XML PATH("") ), 1, 2, "") + "]"
DROP TABLE #Temp
this will create a string for you encasing the names in brackets[] that you can then call later when you pivot the table
QUERY STUFF
PIVOT
(
Some aggregate function(column value)
FOR [Name] IN (' + @Cols + ')
) as P
I know i left a lot out but thought i would at lest share how to build the column names dynamically so that when you add a new row to the approval_levels table it will just add it
Upvotes: 0