我针对Oracle数据库开发.当我需要手动编写(不使用像hibernate这样的ORM)时,我使用WHERE条件而不是JOIN.
例如(这只是用来说明风格的简单化):
Select *
from customers c, invoices i, shipment_info si
where c.customer_id = i.customer_id
and i.amount > 999.99
and i.invoice_id = si.invoice_id(+) -- added to show a replacement for a join
order by i.amount, c.name
Run Code Online (Sandbox Code Playgroud)
我从OLD oracle DBA那里学到了这种风格.我从那时起就知道这不是标准的SQL语法.除了非标准和更少的数据库便携性,使用这种格式还有其他任何影响吗?
Han*_*Gay 16
我不喜欢这种风格,因为它更难以确定哪些WHERE条款用于模拟JOINs,哪些条款用于实际过滤器,我不喜欢使代码更难以确定程序员的原始意图.
Ada*_*ter 10
我遇到这种格式的最大问题是忘记一些连接WHERE条款的倾向,从而导致产生笛卡尔积.在向查询添加新表时,这种情况(对我来说至少是这种情况)很常见.例如,假设一个ADDRESSES表被抛入混合中,你的思想有点健忘:
SELECT *
FROM customers c, invoices i, addresses a
WHERE c.customer_id = i.customer_id
AND i.amount > 999.99
ORDER BY i.amount, c.name
Run Code Online (Sandbox Code Playgroud)
繁荣!笛卡尔积!:)
在某些情况下,旧式连接是错误的(外连接是罪魁祸首).虽然它们在使用内部联接时或多或少相等,但它们可能会在外部联接时生成不正确的结果,尤其是在外侧的列可以为null时.这是因为在使用旧语法时,在构造整个结果集之前不会对连接条件进行逻辑评估,因此根本无法在连接外部的列上表示条件,该列将在列可以过滤记录时为null,因为没有匹配的记录.
举个例子:
选择所有的客户,以及他们在本月8月,在发票已处理所有发票销售窗口小部件的总和(Invoice.ProcessDate是不空)
使用新的ANSI-92 Join语法
Select c.name, Sum(d.Amount)
From customer c
Left Join Invoice I
On i.custId = c.custId
And i.SalesDate Between '8/1/2009'
and '8/31/2009 23:59:59'
And i.ProcessDate Is Not Null
Left Join InvoiceDetails d
On d.InvoiceId = i.InvoiceId
And d.Product = 'widget'
Group By c.Name
Run Code Online (Sandbox Code Playgroud)
尝试使用旧语法执行此操作...因为在使用旧样式语法时,在重新添加"外部"行之前评估/应用where子句中的所有条件,所有未处理的发票行将被添加回到最终的结果集.所以这是不可能用旧的语法 - 任何试图筛选出与空加工日期的发票将消除客户...唯一的选择是使用相关子查询.
有些人会说这种风格的可读性较差,但这是习惯问题.从性能的角度来看,这没关系,因为查询优化器会处理这个问题.