locked
how to get Pivot result set using 3 tables RRS feed

  • Question

  • User1052662409 posted

    Hello, Everyone,

    I have 3 tables in my database. tblAssets contains all assets, tbl_Projects contains all locations and tblLocationAssets contains the location and asset_id and asset quantity on that location.

    select asset_id, asset_name from tblAssets order by asset_id
    
    select asset_id, asset_name , location_id ,quantity from tblLocationAssets order by asset_id
    
    select Sno, Location from tbl_Projects order by Sno

    The output as below

    Capture

    I want a result set like below i.e. All locations should come as columns (either the location contains any assets or not) and all assets come as rows (either any location contains that asset or not)

    Varanasi Dehri-On- Son Garhshankar Azamgarh
    1 Safety Instruction Board 2 (quantity) 0 (quantity) 2 (quantity) 1 (quantity)
    2 White Helmet 1 (quantity) 2 (quantity) 3 (quantity) 0 (quantity)
    3 Safety Shoes 3 (quantity) 5 (quantity) 4 (quantity) 7 (quantity)
    4 Radium Jacket Green 0 (quantity) 1 (quantity) 0 (quantity) 0 (quantity)

    Please suggest.

    Tuesday, September 1, 2020 4:54 PM

Answers

  • User1052662409 posted
       --===== Local variables to hold the 3 different sections of Dynamic SQL.
    DECLARE  @SQL1 VARCHAR(MAX)  -- First part, which is static
            ,@SQL2 VARCHAR(MAX)  -- Second part, which is the dynamic column list of the CROSSTAB
            ,@SQL3 VARCHAR(MAX)  -- Third part, which is also static
    ;
    --===== First part, which is static
     SELECT @SQL1 = '
     WITH CTEAssets AS
    (
     SELECT asset_id, location_id, quantity = SUM(quantity)
       FROM dbo.tblLocationAssets
      GROUP BY asset_id, location_id
    )
     SELECT  Location = TP.location
    '
    ;
    --===== Second part, which is the dynamic column list of the CROSSTAB
     SELECT @SQL2 = ISNULL(@SQL2,'')+REPLACE(REPLACE('
             ,[<<asset_name>>] = SUM(CASE WHEN cteAsst.asset_id = <<asset_id>> THEN cteAsst.quantity ELSE 0 END)'
                    ,'<<asset_name>>',RTRIM([asset_name])) --This is where the other end of the 2 REPLACEs start
                    ,'<<asset_id>>',CONVERT(VARCHAR(10),asset_id))
       FROM dbo.tblAssets
      ORDER BY [asset_id] --This could cause a problem with building @SQL2 but I had no data to check with.
    ;
    --===== Third part, which is also static.
         -- Note that we don't need a join to the tbl_projects table because
         -- that's were we got the info from for the Dynamic SQL above.
     SELECT @SQL3 = '
        FROM      dbo.tbl_Projects TP
      LEFT JOIN CTEAssets      cteAsst ON TP.Sno = cteAsst.location_id 
      
    
      
        group by TP.Location , TP.Sno
    	order by TP.Sno DESC
    ;'
    ;
    --===== Combine the 3 parts of the Dynamic SQL and execute it all as a single query.
       exec (@SQL1+@SQL2+@SQL3)
    ;

    The above was the dynamic sql to achieve the requirement I shared. It is working perfectly.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, September 16, 2020 10:22 AM

All replies

  • User1535942433 posted

    Hi demoninside9,

    As far as I think,you need to join three tables and sum quantity.Just like this:

    Table Asset:

    Table Location:

    Table LocationAsset:

    Sql query:

    select *  from 
    (select a.asset_id, a.asset_name,b.Location,la.quantity
    from LocationAssets la  
    inner join Asset a on a.asset_id=la.asset_id 
    inner join Location b on b.Sno=la.Location_id) AS t
    PIVOT(
    Sum(quantity)
    for Location in( Varanasi,Dehri,Garhshankar,Azamgarh)
    ) AS Tab2 

    Result:

    Best regards,

    Yijing Sun

    Wednesday, September 2, 2020 5:34 AM
  • User1052662409 posted

    select *  from 
    (select a.asset_id, a.asset_name,b.Location,la.quantity
    from LocationAssets la  
    inner join Asset a on a.asset_id=la.asset_id 
    inner join Location b on b.Sno=la.Location_id) AS t
    PIVOT(
    Sum(quantity)
    for Location in( Varanasi,Dehri,Garhshankar,Azamgarh)
    ) AS Tab2 

    select *  from 
    (select a.asset_id, a.asset_name,b.Location,la.quantity
    from tblLocationAssets la  
    inner join tblAssets a on a.asset_id=la.asset_id 
    inner join tbl_Projects b on b.Sno=la.Location_id) AS t
    PIVOT(
    Sum(quantity)
    for Location in( Varanasi,Dehri,Garhshankar,Azamgarh)
    ) AS Tab2 

    There are 51 locations on my table. I need the result for all, either location has an asset or not. I think it should be dynamic.

    Currently, it shows error.

    Msg 8117, Level 16, State 1, Line 1
    Operand data type nvarchar is invalid for sum operator.

    Wednesday, September 2, 2020 5:50 AM
  • User1535942433 posted

    Hi demoninside9,

    Msg 8117, Level 16, State 1, Line 1
    Operand data type nvarchar is invalid for sum operator.

    The SUM() function returns the total sum of a numeric column.I have used int of quantity.You couldn't use nvarchar.

    Best regards,

    Yijing Sun

    Wednesday, September 2, 2020 6:39 AM
  • User1052662409 posted
       --===== Local variables to hold the 3 different sections of Dynamic SQL.
    DECLARE  @SQL1 VARCHAR(MAX)  -- First part, which is static
            ,@SQL2 VARCHAR(MAX)  -- Second part, which is the dynamic column list of the CROSSTAB
            ,@SQL3 VARCHAR(MAX)  -- Third part, which is also static
    ;
    --===== First part, which is static
     SELECT @SQL1 = '
     WITH CTEAssets AS
    (
     SELECT asset_id, location_id, quantity = SUM(quantity)
       FROM dbo.tblLocationAssets
      GROUP BY asset_id, location_id
    )
     SELECT  Location = TP.location
    '
    ;
    --===== Second part, which is the dynamic column list of the CROSSTAB
     SELECT @SQL2 = ISNULL(@SQL2,'')+REPLACE(REPLACE('
             ,[<<asset_name>>] = SUM(CASE WHEN cteAsst.asset_id = <<asset_id>> THEN cteAsst.quantity ELSE 0 END)'
                    ,'<<asset_name>>',RTRIM([asset_name])) --This is where the other end of the 2 REPLACEs start
                    ,'<<asset_id>>',CONVERT(VARCHAR(10),asset_id))
       FROM dbo.tblAssets
      ORDER BY [asset_id] --This could cause a problem with building @SQL2 but I had no data to check with.
    ;
    --===== Third part, which is also static.
         -- Note that we don't need a join to the tbl_projects table because
         -- that's were we got the info from for the Dynamic SQL above.
     SELECT @SQL3 = '
        FROM      dbo.tbl_Projects TP
      LEFT JOIN CTEAssets      cteAsst ON TP.Sno = cteAsst.location_id 
      
    
      
        group by TP.Location , TP.Sno
    	order by TP.Sno DESC
    ;'
    ;
    --===== Combine the 3 parts of the Dynamic SQL and execute it all as a single query.
       exec (@SQL1+@SQL2+@SQL3)
    ;

    The above was the dynamic sql to achieve the requirement I shared. It is working perfectly.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, September 16, 2020 10:22 AM