I would like to construct a query to map products and their associated pictures to match a target database schema. My source database stores SEO URLs for each Product in a Picture table using Product_Picture_Mapping as a two-way mapping table. Each Product table can thus have 0 to n pictures associated with it.
SELECT
Name, Price, SeoFilename
FROM Product prod
JOIN Product_Picture_Mapping map
ON prod.Id = map.ProductId
JOIN Picture pict
ON pict.Id = map.PictureId
Name Price SeoFilename
-----------------------------------
Strawberries 11 strawberry
Strawberries 11 strawberry_1
Pineapples 10 pineapples
Banana 10 banana
Banana 10 banana_1
Orange 11 orange
Unfortunately, the target database’s product table has 0 to 3 SEO URLs stored as fields. This makes writing the query quite difficult as I would need to transpose the source’s rows into named columns like so:
Name Price MainImageUrl OtherImageUrl1 OtherImageUrl2
Banana 10 banana banana_1 null
Orange 11 orange null null
Pineapples 10 pineapples null null
Strawberries 11 Strawberry Strawberry_1 null
I’ve tried using the recommended PIVOT function, but it can only generate aggregate values as it requires an aggregate function. I’ve seen other methods, but they are usually single joins to subqueries.
Here’s a link to my db fiddle: https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=786b419936007c85f7f71f0defe5b829
3
Answers
I think you want conditional aggregation:
This does not produce exactly the result set in your question. But I think it is what you want.
Here is a db<>fiddle.
I would suggest to user Pivot function together with ROW_NUMBER() OVER ( partition by name, price ORDER BY SeoFilename)
The “ROW_NUMBER() OVER (partition by Name, Price ORDER BY SeoFilename)” created a sequence number (“1″,”2″,”3” etc) for each rows by different name and price.
The Pivot function will transpose the result for by name and price based on the sequence number given from the seqnum column.
The trick is twofold. First you need to add a way to partition the data per name. Rownumber will aid in this. Secondly you need to pivot the old fashion way.
Rownumber is windowed function and you can add a partition to it. this partition is needed to determine if something will be the first, second, third transposed column. The only downside to this method, is the need to hardcode the amount of transposed columns
Old fashioned pivots work with group by and case when statements. To circumvent the required aggregation, you can use the MAX statement, since the case when will basically ignore the max statement.