user3534188
user3534188

Reputation: 11

Adding columns to a query from the results of another query

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

Answers (3)

cyan
cyan

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

user3175748
user3175748

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

RustyH
RustyH

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

Related Questions