我有一个表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语句具有不同的列数。
这可能......以及如何?
答案 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;
这将有效,假设表C
和D
没有多个匹配的行。如果是这种情况,您可能需要预先聚合结果或使用子查询。
答案 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
可能是您的最佳选择。