别名派生表是两个选择的并集

时间:2011-11-29 13:38:34

标签: sql union

我无法正确地对派生表的别名进行语法处理:

SELECT * FROM 
  (SELECT a.*, b.* 
    FROM a INNER JOIN b ON a.B_id = b.B_id
    WHERE a.flag IS NULL AND b.date < NOW()
  UNION
  SELECT a.*, b.* 
    FROM a INNER JOIN b ON a.B_id = b.B_id
    INNER JOIN c ON a.C_id = c.C_id
    WHERE a.flag IS NOT NULL AND c.date < NOW())
  AS t1
ORDER BY RAND() LIMIT 1

我收到了B_id的重复列名。有什么建议吗?

3 个答案:

答案 0 :(得分:5)

问题不是union,而是每个内部选择语句中的select a.*, b.* - 因为ab都有B_id列,这意味着你在结果中有两个B_id列。

您可以通过将选择更改为以下内容来解决此问题:

select a.*, b.col_1, b.col_2 -- repeat for columns of b you need

通常,我会避免在您从代码中使用的查询中使用select table1.*(而不仅仅是交互式查询)。如果有人在表中添加了一列,则各种查询可能会突然停止工作。

答案 1 :(得分:3)

在派生表中,您正在检索表a和表b中存在的列ID,因此您需要选择其中一个或为它们提供别名:

SELECT * FROM 
  (SELECT a.*, b.[all columns except id] 
    FROM a INNER JOIN b ON a.B_id = b.B_id
    WHERE a.flag IS NULL AND b.date < NOW()
  UNION
  SELECT a.*, b.[all columns except id]  
    FROM a INNER JOIN b ON a.B_id = b.B_id
    INNER JOIN c ON a.C_id = c.C_id
    WHERE a.flag IS NOT NULL AND c.date < NOW())
  AS t1
ORDER BY RAND() LIMIT 1

答案 2 :(得分:1)

首先,您可以使用UNION ALL代替UNION。由于a.flag上的排除条件,两个子查询将没有公共行。

你可以写的另一种方式是:

SELECT a.*, b.* 
FROM a 
  INNER JOIN b 
    ON a.B_id = b.B_id
WHERE ( a.flag IS NULL 
      AND b.date < NOW()
      )
   OR
      ( a.flag IS NOT NULL 
      AND EXISTS
          ( SELECT *
            FROM c 
            WHERE a.C_id = c.C_id
              AND c.date < NOW()
          )
      )
ORDER BY RAND() 
LIMIT 1