Question

I want to create an SQL report that shows an ordered stock list for a chain of record stores to show the current stock status of each: Nirvana, Mission of Burma and Wipers album, assuming each store only contains one album at any given time (for the sake of simplicity).

My SQL query currenty only shows whether or not each band has an album in stock I want to be able to show the stock level of every album so I think that I require some sort of nested return and possibly to use a pivot-table instead of Left Outer Joins.


Drop table #AlbumStock 
Drop table #MissionOfBurma 
Drop table #Wipers
Drop table #Nirvana
go

CREATE TABLE #AlbumStock 
( Store varchar(Max),
  Artist varchar(Max),
  Album varchar(Max),
  AlbumID int 
)
go

INSERT INTO #AlbumStock 
    (Store,Artist,Album,AlbumID)
VALUES 
    ('Glasgow','Wipers', 'Over the Edge', 3),
    ('Glasgow', 'Nirvana', 'Bleach', 1),
    ('Glasgow', 'Nirvana', 'Unplugged In New York', 4),
    ('Glasgow', 'Mission of burma', 'VS', 1),
    ('Leeds', 'Wipers', 'Over the Edge', 3), 
    ('Leeds','Wipers', 'Youth of America', 2),
    ('Leeds', 'Nirvana', 'Bleach', 1),
    ('Leeds', 'Nirvana', 'Nevermind', 2),
    ('Manchester', 'Wipers', 'Over the Edge', 3),
    ('Manchester', 'Wipers', 'Youth of America', 2),
    ('Manchester', 'Wipers', 'Is this real?', 1),
    ('Manchester', 'Wipers', 'Land of the lost', 4)


Select MAX(AlbumID) As FirstID, Store 
Into #MissionOfBurma 
From #AlbumStock 
Where Artist = 'Mission of burma'
Group BY Store

Select MAX(AlbumID) As FirstID, Store
Into #Wipers 
From #AlbumStock 
Where Artist = 'Wipers'
Group BY Store

Select MAX(AlbumID) As FirstID, Store  
Into #Nirvana 
From #AlbumStock 
Where Artist = 'Nirvana'
Group BY  Store

-- Current Reporting Query

Select stock.Store, ISNULL(mob.FirstID,0) As Mission_of_Burma_ID, 
    ISNULL(wip.FirstID,0) As Wipers_ID, ISNULL(nir.FirstID,0) As Nirvana_ID 
From (Select Store 
      From #AlbumStock 
      Group BY Store ) as stock  
LEFT OUTER JOIN
 #MissionOfBurma as mob 
 ON
 mob.Store = stock.Store
LEFT OUTER JOIN
 #Wipers as wip
 ON
 wip.Store = stock.Store
 LEFT OUTER JOIN
 #Nirvana as nir
 ON
 nir.Store = stock.Store

The output from the query is this:

╔════════════╦═════════════════════╦═══════════╦════════════╗
║ Store      ║ Mission_of_Burma_ID ║ Wipers_ID ║ Nirvana_ID ║
╠════════════╬═════════════════════╬═══════════╬════════════╣
║ Glasgow    ║ 1                   ║ 3         ║ 4          ║
║ Leeds      ║ 0                   ║ 3         ║ 2          ║
║ Manchester ║ 0                   ║ 4         ║ 0          ║
╚════════════╩═════════════════════╩═══════════╩════════════╝

And I would like it to be something more like this:

╔════════════╦═════════════════════╦═══════════╦════════════╗
║ Store      ║ Mission_of_Burma_ID ║ Wipers_ID ║ Nirvana_ID ║
╠════════════╬═════════════════════╬═══════════╬════════════╣
║ Glasgow    ║ 1                   ║ 3         ║ 1  ║ 4     ║
║ Leeds      ║ 0                   ║ 2   ║  3  ║ 1  ║ 2     ║
║ Manchester ║ 0                   ║1 ║ 2║ 3║4 ║ 0          ║
╚════════════╩═════════════════════╩═══════════╩════════════╝

Any advice/guidance would be greatly appreciated.

Was it helpful?

Solution

The first problem you are facing is that SqlServer doesn't have an equivalent of MySql's GROUP_CONCAT, nor does it have a generic aggregate Fold capability. So you'll need to use one of these hacks to get the comma delimited list of stock, e.g. STUFF / FOR XML PATH:

SELECT Store, Artist, 
   STUFF((SELECT ',' + CAST(albumID AS VARCHAR(10)) 
   FROM #AlbumStock a 
   WHERE a.Store = x.Store AND a.Artist = x.Artist 
   FOR XML PATH ('')), 1, 1, '') AS Stuffed
FROM
(
   SELECT Store, artist
   FROM #AlbumStock
   GROUP BY Store, Artist
) x;

Which results in this:

Store       Artist                Stuffed
----------- --------------------------------
Glasgow     Mission of burma      1
Glasgow     Nirvana               1,4
Glasgow     Wipers                3
Leeds       Nirvana               1,2
Leeds       Wipers                3,2
Manchester  Wipers                3,2,1,4

To transform this with each Artist as a Column, you'll need a PIVOT

WITH cteStuffed AS
(
   SELECT Store, Artist, 
      STUFF((SELECT ',' + CAST(albumID AS VARCHAR(10)) 
      FROM AlbumStock a 
      WHERE a.Store = x.Store AND a.Artist = x.Artist 
      FOR XML PATH ('')), 1, 1, '') AS Stuffed
   FROM
   (
      SELECT Store, artist
      FROM AlbumStock
      GROUP BY Store, Artist
   ) x
)
SELECT Store, [Mission of burma], [Wipers], [Nirvana]
FROM
   cteStuffed
PIVOT
(
 MIN(Stuffed)
 for [Artist] IN ([Mission of burma], [Wipers], [Nirvana])
)pvt;

SqlFiddle here

This then gives you the table you need, although I guess there are a couple of loose ends:

  • You might want to use ISNULL or COALESCE to replace the NULLs with Zeroes.
  • You will probably want to determine the columns dynamically from the data. To do this, you'll need to resort to dynamic Sql - have a look at how BlueFeet does this here
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top