根据列值连接不同的表

时间:2014-06-12 12:12:23

标签: sql join

我有一个表R,它包含表P的外键。在表P中有一列,告诉我表P中的记录是哪种类型。与列中的可能值相关。存在根据表格的类型。因此,如果P.type为'C',则表示名为C的表,如果值为'D',则表示名为D的表。

现在我想要一个SELECT语句,它根据P.type分别给出表C或D中的值。 为了使它更复杂,结果中列的数量/类型应该不同。

SELECT r.id, r.pid, p.type, 
FROM R r 
LEFT JOIN P p ON r.pid = p.pid 
WHERE r.id = 123 LIMIT 1;

现在我已经获得了P表的记录。根据列类型的值,我想决定在先前的查询中要加入哪个表(C或D)。 如果我必须连接表D,则返回的列(结果集)应该是原样但如果必须连接表C,则应返回另一列。因此,SELECT子句从

更改

SELECT r.id,r.pid,p.type FROM ...

SELECT r.id,r.pid,p.type,c.name FROM ...

Preudocode:

SELECT r.id, r.pid, p.type(, c.name)   -- c.name my or may not be in the result depending on the joined table
FROM R r 
LEFT JOIN P p ON r.pid = p.pid 
if p.type = 'D' LEFT JOIN D d ON d.pid = p:pid end
if p.type = '' LEFT JOIN C c ON c.pid = p:pid end
WHERE r.id = 123 LIMIT 1;

有可能加入的可能表的数量可能会扩展(p.type的值可能会从C和D增加到E,F,G,......)我宁愿只加入ONE由p.type指定的表,而不是在所有可能的表之上使用UNION。 因此...由于结果中的列数不同,UNION尝试以错误代码1222结束:

  

使用的SELECT语句具有不同的列数。

这可能......以及如何?

2 个答案:

答案 0 :(得分:1)

您的伪代码可以实现为:

SELECT r.id, r.pid, p.type, coalesce(d.name, c.name)  
FROM R r LEFT JOIN
     P p
     ON r.pid = p.pid LEFT JOIN 
     D d
     ON p.type = 'D' and d.pid = p.pid LEFT JOIN
     C c
     ON p.type = '' and c.pid = p.pid end
WHERE r.id = 123
LIMIT 1;

这将有效,假设表CD没有多个匹配的行。如果是这种情况,您可能需要预先聚合结果或使用子查询。

答案 1 :(得分:0)

@ GordonLinoff回答的一个类似但另类的答案是将表C和D组合成一个表。

可以使用真正的单个表格,视图或内联视图来完成,后者我将在下面显示...

SELECT
  r.id,
  r.pid,
  p.type,
  z.name
FROM
  R   AS r
LEFT JOIN
  P   AS p
    ON r.pid = p.pid
LEFT JOIN
(
  SELECT 'D' AS type, pid, ''   AS name FROM D
  UNION ALL
  SELECT ''  AS type, pid, name AS name FROM C
)
  AS z
    ON  z.type = p.type
    AND z.pid  = p.pid
WHERE
  r.id = 123
LIMIT
  1
;

此结构通常可以通过减少重复来简化代码,但也可以帮助优化器(取决于索引等),以减少连接中所需的工作量。

注意:因为Unioned表在第一个字段中有标量常量,并且因为该字段用于连接,所以优化器能够(取决于RDBMS)避免尝试冗余连接两张桌子上。 (提供足够的信息以了解要加入的表格。)

编辑: 根据OP发表的评论

如果两个表的差别足以使UNION ALL变得不切实际,那么使用两个LEFT JOIN可能是您的最佳选择。