Sql 将where子句分解为子查询

Sql 将where子句分解为子查询,sql,postgresql,Sql,Postgresql,我想知道在SQL中,是否总是可以通过子查询的连接来考虑where条件。例如,如果我有 select ... from a join b on ... where p and q 而p仅适用于a,q适用于b,那么我可以随时重写为吗 select ... from (select ... from a where p) as a join (select ... from b where q) as b on ... 谢谢 [注意:1)我正在使用postgres,以防这会影响答案。2)可读性不是

我想知道在SQL中,是否总是可以通过子查询的连接来考虑where条件。例如,如果我有

select ... from a join b on ... where p and q
p
仅适用于
a
q
适用于
b
,那么我可以随时重写为吗

select ... from (select ... from a where p) as a join (select ... from b where q) as b on ...
谢谢


[注意:1)我正在使用postgres,以防这会影响答案。2)可读性不是一个重要的考虑因素,因为这些是自动生成的查询。编辑::3)我不仅对内部联接感兴趣,而且对其他联接也感兴趣。]

我会说是的,我想不出不可能的情况。其中,可以用连接替换其自身:

select ... from A where x=10
<=>
select ... from A join ( values (10) ) B (x) on A.x = B.x
选择。。。从A开始,其中x=10
选择。。。从A.x=B.x上的连接(值(10))B(x)

可能是离题了,但对于一般的转换,Vadim Tropashko()表明可以将经典关系代数运算符集简化为两个二进制运算:自然联接和广义并集

SELECT ...
FROM TableA
JOIN TableB ON <SomeForeignKey>
JOIN TableC ON <SomeForeignKey>
WHERE <SomeConditionOnTableA> AND
      <SomeConditionOnTableB> AND
      <SomeConditionOnTableC>
选择。。。
从表格
加入表B
加入表3
在哪里
及
。。。相当于查询2:

SELECT ...
FROM TableA
JOIN TableB ON <SomeForeignKey> AND <SomeConditionOnTableB>
JOIN TableC ON <SomeForeignKey> AND <SomeConditionOnTableC>
WHERE <SomeConditionOnTableA>
选择。。。
从表格
将表B和
将表C和
哪里
但如果使用外部联接而不是(内部)联接,则情况并非如此。对于外部联接,等价性适用于匹配非空列值的非常简单的条件,如:

name='value'
name LIKE '%value%'
number < const
field IN (...)
name='value'
名称类似于“%value%”
数量<常数
字段在(…)
请注意,这些都是使外部联接仍然有效的条件,因为它们过滤掉了在已解析列中具有空值的行。。。因此,它们也会过滤掉外部联接添加的行,而不会从联接表中检索任何内容

但如果使用外部联接并开始将列值与空值进行比较或比较可能包含空值的表达式,则等价性将中断

例如,以该查询(格式化为查询1)为例:

选择。。。
从表a
左键连接表b打开
左连接表c打开
其中a.somefield='whatever'
并且b.name不为空
c.某些数字大于100
在这种情况下,将在解析外部联接后应用筛选器,它将删除TableB中存在且名称为空的行,但也会删除外部联接添加的、在TableB中找不到匹配行的行。这不等同于查询2格式:

SELECT ...
FROM      TableA a
LEFT JOIN TableB b ON <SomeForeignKey> AND b.name IS NOT NULL
LEFT JOIN TableC c ON <SomeForeignKey> AND c.somenumber >100
WHERE a.somefield = 'whatever'
选择。。。
从表a
左联接表b打开且b.name不为空
左连接表c ON和c.somenumber>100
其中a.somefield='whatever'

在这种情况下,在解析外部联接之前,将筛选器应用于表B。具有空名称的TableB行由筛选器消除,但由左联接重新引入。因此,此查询可能包含前者不包含的行。

为什么不选择。。。从a到b在(…和q)上,其中p?我的意思是,为什么不把条件直接放在join的ON子句中呢?当然,第一张桌子上的条件必须保持在何处。使用subselect可能会阻碍查询执行优化。1)将条件置于“开”是否有任何区别?2) 如果使用子选择可能会阻碍优化,那么我是否应该尝试将条件考虑在内?我认为,如果条件使连接的一侧小得多,那么考虑因素也会有所帮助。将条件放入连接中不会影响结果。但是将所有条件放在一个表中可能有助于优化器完成其工作。等等。。。您还说您对外部联接也感兴趣。这稍微改变了一些情况。WHERE中的条件不能移动到外部联接的ON子句或子选择中,而不会产生任何后果。至少不总是这样。这取决于条件和空值。啊哈。。。好吧——这就是我担心的情况。:)所以让我们看看:如果我在外部有一个条件,过滤掉“a”中一行的所有匹配项,然后在内部加上,那么我将得到a中的一行,其中b为null。谢谢——我知道有一个美中不足的地方,但我忘了在哪里。如果你写下来作为回答,我会接受的……谢谢你的推荐。隐马尔可夫模型。。。这也适用于外部联接?我也想不出什么,只记得我脑子里有一件奇怪的边缘案件。
SELECT ...
FROM      TableA a
LEFT JOIN TableB b ON <SomeForeignKey> AND b.name IS NOT NULL
LEFT JOIN TableC c ON <SomeForeignKey> AND c.somenumber >100
WHERE a.somefield = 'whatever'