【问题标题】:postgres: Trying to join 4 tables based on a conditionalpostgres:尝试根据条件连接 4 个表
【发布时间】:2017-06-30 12:59:14
【问题描述】:

我有 4 张桌子。 table1 有一列称为reportable_type,另一列称为reportable_id。可报告类型有两个值,table2 或 table3。 table2 和 table3 都有一个 table4_id 列。我正在尝试编写一个查询,让我在一个结果中获得 table1.id 和 table4.description。感觉就像一个关于 postgres 的案例陈述会让我到达那里,但我迷路了,还有两个案例陈述可能打破了这一点:

select t1.id, t4.description 
from table1 as t1
case 
  when t1.reportable_type = ’table2’
    then left join table2 as t2 on t1.reportable_id = t2.id
    else left join table3 as t3 on t1.reportable_id = t3.id
end
left join table4 as t4 on 
case 
  when t1.reportable_type = ’table2’
    then t2.table4_id =t4.id
    else t3.table4_id =t4.id
end
group by t4.description;

编辑:
想围绕这个添加一些数据,这样更清楚。 让我们使用以下数据:

table 1
IDs - 1, 2
reportable_type - table 2, table 3
reportable_id - 1, 1 

table 2:
id - 1
t4_id - 1

table 3:
id - 1
t4_id - 2

table 4:
id - 1 ,2
description - first, second

所以查询的结果表应该是:

id - 1,2
description - first, second 

【问题讨论】:

  • 你不能随心所欲地改变语法规则。具体来说,casefrom 子句中没有位置,我相信您知道。把它放在它确实有位置的地方——在select列表中。
  • 除非 postgresql 有很大的不同,否则你不能在连接中使用这种方式。您可以在每次检查 table2 或不检查 table2 时创建一个“AND 语句;但是这种大小写的使用似乎很奇怪。
  • 同意,我在这里遇到的问题是我不确定如何让这种关系发挥作用。完全同意上述语法不起作用,但认为它会让我更清楚地了解我想要做什么。
  • @xQbert 我不确定如何使用 and 语句来确定要加入哪个表的条件。你能扩展一下吗?
  • 您可以左连接所有需要的表,然后有条件地在选择中显示您需要的表中的数据,但您不能有条件地连接,除非您进入更多程序化的 SQL。

标签: postgresql join case


【解决方案1】:

我们必须在 t2 和 t3 上留下连接,因为 t1.reportable_Type 不能是 'table2' 和 = table2,因此只有 1 会解决。然后我们可以coalesce从T3,t2中的任一ID到t4的关系值。

这确实意味着必须尝试解决两个左连接,因此它可能不如尝试弄清楚如何仅执行一个左连接那么有效。但结果应该是准确的。一旦你得到这个工作,如果性能是一个问题,我们需要查看执行计划/索引,看看是否有其他方法来优化它。

SELECT t1.id, t4.description 
FROM table1 as t1
LEFT join table2 as t2 
  on t1.reportable_id = t2.id
 and t1.reportable_type = 'table2'
LEFT join table3 as t3 
  on t1.reportable_id = t3.id
 and coalesce(t1.reportable_type,'isNull') <> 'table2'
LEFT join table4 as t4
  on t4.id = coalesce(t2.table4_id, t3.table4_ID)
--GROUP BY t4.description;

不知道为什么你有一个不带聚合的分组。所以我把它注释掉了;也许你的意思是ORDER BY;我通常认为在几乎所有查询中都包含 order by 是明智的;尤其是那些可以利用索引的。

如果 t1.reportable_type 为空,我还添加了 and coalesce(t1.reportable_type,'isNull') &lt;&gt; 'table2' 以使用合并来处理这种情况。我假设您仍然想要这些记录,因为 null 不等于 'table2' 但您可能根本不想要这些记录;所以我们需要有关该特定案例的更多信息。

t3 上的 连接条件也可能有点消耗性能,因为我不相信可以使用索引。但我不确定如何解决它,但也许 in 或 exists 和子查询会起作用......但我会让你从这里开始玩。

【讨论】:

  • 哇,这正是我想要的。很高兴能研究一些我在 coalesce 和 中从未听说过的事情。非常感谢。
  • &lt;&gt; 只是 != 两者都不相等。我更喜欢&lt;&gt;!=。并且 coalesce 只是返回一系列值中的第一个非 null 值,因此我们可以 coalesce(varA, varB, varC, 'Error') 如果我们想要并且如果 a、b、c 都是 null 将返回错误(我相信 coalese 确实要求所有数据类型都是但是一样)。在这种情况下,因为我们知道两者之一将始终具有价值,因此合并应该起作用。还要记住连接上的&lt;&gt; 意味着没有索引可以用于该标准;因此,如果表大小增加,性能可能会很差。
  • 在合并上会不会引起问题,因为 id 值只是增加整数,t2 和 t3 都可能有相似的 id?或者 on/and 子句是否选择正确的表来关联给定的行?
  • 让我们看看你的例子中的伪逻辑:同样的问题在那里不适用吗?如果 t2 和 t3 中的 table4_ID 重叠,那么我们需要一个附加元素来作为 T4 连接的基础。而且由于reportable_type 不在t4 中...我看不出我们可以限制什么。我需要更多信息和一些示例数据;显示这种情况和预期的结果。现在请记住,在 t2 中,t3 左连接只有其中一个具有值,另一个将始终为空;所以它首先只能加入一张桌子。
  • 另一方面,如果 t1.reportable_type 可以为 null,则 将失败,因此我们可能需要 coalesce(t1.reportable_type,'isNull') 才能正确处理 Null 值。否则我们不会处理所有的 t1.reportable_type 可能性。 (意味着某些记录可能不会显示,因为 NULL 无法在 上进行评估,它返回 null,这是不正确的,因此任何此类数据都不会在连接中返回)这是危险之一,并且 Null 和 或不在。通常情况下,尽可能使用 = vs &lt;&gt; 更好;避免 Null 情况并使用索引提供帮助
猜你喜欢
  • 1970-01-01
  • 2016-11-18
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多