12 March 2025

MySQL UNION QUERY


🔹 Scenario

We have two tables:

  • blog_posts - Stores blog post titles and metadata.
  • post_contents - Stores different content sections for each post.

📌 Sample Data

1️⃣ blog_posts

idtitleauthor_idcreated_at
1First Post22024-03-10
2Second Post32024-03-11
3Third Post42024-03-12

2️⃣ post_contents

idpost_idcontentcontent_type
11"Intro text...""intro"
21"Main content...""body"
32"Another post...""body"

📝 SQL Query

SELECT 
    bp.id AS post_id, 
    bp.title AS post_title, 
    pc.content, 
    pc.content_type
FROM blog_posts bp
LEFT JOIN post_contents pc ON bp.id = pc.post_id

UNION

SELECT 
    bp.id AS post_id, 
    bp.title AS post_title, 
    NULL AS content, 
    'no content' AS content_type
FROM blog_posts bp
WHERE bp.id NOT IN (SELECT post_id FROM post_contents);
                

🔹 Explanation

1️⃣ The first part of the UNION query:

  • Fetches blog post titles and their related content.
  • Uses a LEFT JOIN so all blog posts appear, even if they don’t have content.

2️⃣ The second part of the UNION:

  • Retrieves posts that have no content (ensures all posts are included).
  • Assigns NULL to content and marks content_type as 'no content'.

✅ Expected Output

post_idpost_titlecontentcontent_type
1First Post"Intro text...""intro"
1First Post"Main content...""body"
2Second Post"Another post...""body"
3Third PostNULL"no content"

Alternative: Use GROUP_CONCAT for Compact Results

If you want one row per post with all content combined, use GROUP_CONCAT:

SELECT 
    bp.id AS post_id, 
    bp.title AS post_title, 
    GROUP_CONCAT(pc.content ORDER BY pc.content_type SEPARATOR ' | ') AS content
FROM blog_posts bp
LEFT JOIN post_contents pc ON bp.id = pc.post_id
GROUP BY bp.id, bp.title;
                

✅ This will output content as a single row per post.