Reputation: 3
My case is as follow:
I have a table articles
with these details:
article | image1 | image2 | image3
---------------------------------
1 | im-x
2 | im-y
3 | im-z
and other article_images table with this data:
article | image
---------------
1 | im-a
1 | im-b
2 | im-c
2 | im-d
3 | im-e
I need to update the table articles like this:
article | image1 | image2 | image3
---------------------------------
1 | im-x | im-a | im-b
2 | im-y | im-c | im-d
3 | im-z | im-e |
I know it seems not very difficult, but impossible to find an example on google. Can anyone help me, please?
Upvotes: 0
Views: 389
Reputation: 22855
This query will produce the desired Pivot:
SELECT a.article, coalesce(i1.image,'') AS img1, coalesce(i2.image, '') AS img2
FROM (SELECT article FROM article_images GROUP BY article) a
LEFT JOIN article_images i1 ON a.article = i1.article AND i1.image =
(SELECT image FROM article_images WHERE article = a.article
ORDER BY image LIMIT 1)
LEFT JOIN article_images i2 ON a.article = i2.article AND i2.image =
(SELECT image FROM article_images WHERE article = a.article
ORDER BY image LIMIT 1 OFFSET 1);
A bit complicated, but this subquery will work in MySQL + PostgreSQL.
To update use (this UPDATE
is MySQL specific):
UPDATE articles a, (SELECT a.article, coalesce(i1.image, '') AS img1,
coalesce(i2.image, '') AS img2
FROM (SELECT article FROM article_images GROUP BY article) a
LEFT JOIN article_images i1 ON a.article = i1.article AND i1.image =
(SELECT image FROM article_images WHERE article = a.article
ORDER BY image LIMIT 1)
LEFT JOIN article_images i2 ON a.article = i2.article AND i2.image =
(SELECT image FROM article_images WHERE article = a.article
ORDER BY image LIMIT 1 OFFSET 1)) AS s
SET a.image2 = s.img1, a.image3 = s.img2
WHERE a.article = s.article;
If your database support window functions + CTE, like SQL Server, PostgreSQL or ORACLE, the following query can be used instead to generate Pivot:
WITH rowed AS (
SELECT article, image,
row_number() OVER (PARTITION BY article ORDER BY image) AS row
FROM article_images)
SELECT a.article, coalesce(i1.image, '') AS img1, coalesce(i2.image, '') AS img2
FROM (SELECT article FROM article_images GROUP BY article) AS a
LEFT JOIN rowed i1 ON i1.article = a.article AND i1.row = 1
LEFT JOIN rowed i2 ON i2.article = a.article AND i2.row = 2;
Now you have a single row per article in a shorter way and you can use this subquery to update:
UPDATE articles a
SET image2 = s.img1,
image3 = s.img2
FROM (WITH rowed AS (
SELECT article, image,
row_number() OVER (PARTITION BY article ORDER BY image) AS row
FROM article_images)
SELECT a.article, coalesce(i1.image, '') AS img1, coalesce(i2.image, '') AS img2
FROM (SELECT article FROM article_images GROUP BY article) AS a
LEFT JOIN rowed i1 ON i1.article = a.article AND i1.ROW = 1
LEFT JOIN rowed i2 ON i2.article = a.article AND i2.ROW = 2) AS s
WHERE a.article = s.article;
This UPDATE
query will work in PostgreSQL, but likely it wont on ORACLE / SQL Server.
You can play around with MySQL and PostgreSQL variants.
Upvotes: 1
Reputation: 69759
Your current approach with a separate "article_images" table is the best approach. This kind of table is the bread and butter of a relational database! If it is essential that you have an article with the first 3 images in the same row then I would suggest creating a view, and keeping your current table structure. The view could be defined as:
SELECT ar.Article,
MIN(img1.Image) AS Image1,
MIN(img2.Image) AS Image2,
MIN(img3.Image) AS Image3
FROM Articles ar
LEFT JOIN Article_images img1
ON img1.Article = ar.Article
LEFT JOIN Article_images img2
ON img2.Article = ar.Article
AND img2.Image > img1.Image
LEFT JOIN Article_images img3
ON img3.Article = ar.Article
AND img3.Image > img2.Image
GROUP BY ar.Article
Upvotes: 1
Reputation: 5758
If you can add an additional colum to the article_images table and identify which colum the image needs to go in:
article | image | col
------------------------
1 | im-a | image2
1 | im-b | image3
2 | im-c | image3
2 | im-d | image2
3 | im-e | image3
Then this should work:
update articles
set image1 = CASE WHEN col = 'image1' THEN image else image1 END,
image2 = CASE WHEN col = 'image2' THEN image else image2 END,
image3 = CASE WHEN col = 'image3' THEN image else image3 END
from articles inner join article_images
on articles.article = article_images.article
Upvotes: 1