Julio Argente
Julio Argente

Reputation: 3

Update columns in one table from rows of another table

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

Answers (3)

vyegorov
vyegorov

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

GarethD
GarethD

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

Live Test at SQL Fiddle

Upvotes: 1

web_bod
web_bod

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

Related Questions