即使使用GROUP BY,MySQL UNION查询也会返回重复值

时间:2018-05-28 16:10:41

标签: mysql

我有以下查询:

SELECT *
FROM (
    SELECT 
        m.id AS id,
        reference_id, 
        title, 
        created_by, 
        publish_up, 
        state 
    FROM z_news_master m  
    LEFT JOIN z_news_english c ON m.id = c.reference_id
    WHERE c.created_by = 17152
    ORDER by c.id DESC
) AS A

UNION

SELECT * FROM (
    SELECT 
        m.id AS id, 
        reference_id,
        title, 
        created_by, 
        publish_up, 
        state 
    FROM z_news_master m  
    LEFT JOIN z_news_spanish c ON m.id = c.reference_id
    WHERE c.created_by = 17152
    ORDER by c.id DESC 
) AS B
GROUP BY id 

基本上,我有3个表(z_news_master, z_news_english, z_news_spanish),用西班牙语或英语存储新闻。 z_news_master表包含通用新闻信息,z_news_englishz_news_spanish包含各自语言的新闻。

我需要获取新闻列表,如果新闻在两个语言表中,它应该只返回一个(不重复),上面的代码可以完成工作,但如果有新的英语和西班牙语,记录重复。

我也想知道为什么GROUP BY idGROUP BY reference_id不起作用?

2 个答案:

答案 0 :(得分:1)

如果存在首选语言的相应行,请使用NOT EXISTS子查询删除后备语言行。假设首选语言为“english”,则查询为:

SELECT 
    m.id AS id,
    reference_id, 
    title, 
    created_by, 
    publish_up, 
    state 
FROM z_news_master m  
JOIN z_news_english c ON m.id = c.reference_id
WHERE c.created_by = 17152

UNION ALL

SELECT 
    m.id AS id, 
    reference_id,
    title, 
    created_by, 
    publish_up, 
    state 
FROM z_news_master m  
JOIN z_news_spanish c ON m.id = c.reference_id
WHERE c.created_by = 17152
  AND NOT EXISTS (
    SELECT *
    FROM z_news_english e
    WHERE e.reference_id = m.id
      AND e.created_by = c.created_by
  )

ORDER by id DESC

请注意,不需要GROUP BY。 LEFT JOIN没有意义,因为右表中的列有一个WHERE条件(将LEFT JOIN转换为INNER JOIN)。

答案 1 :(得分:0)

您可以在不使用联合的情况下执行此操作。下面的语句从主表中获取所有行,并连接西班牙语和英语表中的所有现有行。 如果西班牙语表中存在行,则它使用该表中的值。如果英语表中存在行,而不是西班牙语表,则它使用该表中的值。 如果英语或西班牙语表中不存在匹配的行,则返回主表中的列。

您可以通过更改WHEN的顺序来更改优先级。

SELECT 
    CASE 
        WHEN NOT s.id IS NULL THEN s.id 
        WHEN NOT e.id IS NULL THEN e.id 
        ELSE m.id AS `id`, 
    CASE 
        WHEN NOT s.reference_id IS NULL THEN s.reference_id 
        WHEN NOT e.reference_id IS NULL THEN e.reference_id 
        ELSE m.reference_id AS `reference_id`, 
    CASE 
        WHEN NOT s.title IS NULL THEN s.title 
        WHEN NOT e.title IS NULL THEN e.title 
        ELSE m.title AS `title`, 
    CASE 
        WHEN NOT s.created_by IS NULL THEN s.created_by 
        WHEN NOT e.created_by IS NULL THEN e.created_by 
        ELSE m.created_by AS `created_by`, 
    CASE 
        WHEN NOT s.publish_up IS NULL THEN s.publish_up 
        WHEN NOT e.publish_up IS NULL THEN e.publish_up 
        ELSE m.publish_up AS `publish_up`, 
    CASE 
        WHEN NOT s.state IS NULL THEN s.state 
        WHEN NOT e.state IS NULL THEN e.state 
        ELSE m.state AS `state`
FROM z_news_master m  
LEFT JOIN z_news_spanish s ON m.id = s.reference_id
LEFT JOIN z_news_english e ON m.id = e.reference_id
WHERE m.created_by = 17152
ORDER by m.id DESC 
GROUP BY m.id 

修改

Per Paul Spiegel的评论这是一个更短的版本:

SELECT 
    COALESCE(s.id, e.id, m.id) AS `id`, 
    COALESCE(s.reference_id, e.reference_id, m.reference_id) AS `reference_id`, 
    COALESCE(s.title, e.title, m.title) AS `title`, 
    COALESCE(s.created_by, e.created_by, m.created_by) AS `created_by`, 
    COALESCE(s.publish_up, e.publish_up, m.publish_up) AS `publish_up`, 
    COALESCE(s.state, e.state, m.state) AS `state`
FROM z_news_master m  
LEFT JOIN z_news_spanish s ON m.id = s.reference_id
LEFT JOIN z_news_english e ON m.id = e.reference_id
WHERE m.created_by = 17152
ORDER by m.id DESC 
GROUP BY m.id