如果要在SQL查询中连接多个表,您认为在哪里放置连接语句是更好的地方:在FROM子句或WHERE子句中?
如果要在FROM子句中执行此操作,如何对其进行格式化以使其清晰可读? (我说的是缩进,换行,一般的空格。)
每个都有任何优点/缺点吗?
答案 0 :(得分:8)
我倾向于使用FROM
子句,或者更确切地说是JOIN
子句本身,这样缩进(并使用别名):
SELECT t1.field1, t2.field2, t3.field3
FROM table1 t1
INNER JOIN table2 t2
ON t1.id1 = t2.id1
INNER JOIN table3 t3
ON t1.id1 = t3.id3
这使连接条件保持接近连接的位置。我发现通过这种方式更容易理解,然后尝试查看WHERE
子句以找出究竟加入的方式。
答案 1 :(得分:6)
在进行OUTER JOIN(ANSI-89或ANSI-92)时,过滤位置很重要,因为ON
子句中指定的条件在JOIN生成之前应用 。在WHERE
子句中提供的OUTER JOINed表的标准在JOIN生成后应用。这可以产生非常不同的结果集。
相比之下,如果ON
或WHERE
条款中提供了条件,则INNER JOIN无关紧要 - 结果将是相同的。也就是说,我努力保持WHERE
子句清洁 - 与JOINed表相关的任何内容都将在各自的ON
子句中。通过WHERE子句保存搜索,这就是ANSI-92语法更易读的原因。
答案 2 :(得分:1)
我几乎总是使用ANSI 92连接,因为它清楚地表明这些条件适用于JOINING。
通常我会这样写
FROM
foo f
INNER JOIN bar b
ON f.id = b.id
有时我会以这种方式写它,这很简单
FROM
foo f
INNER JOIN bar b ON f.id = b.id
INNER JOIN baz b2 ON b.id = b2.id
当它不是微不足道时,我会做第一种方式
e.g。
FROM
foo f
INNER JOIN bar b
ON f.id = b.id
and b.type = 1
或
FROM
foo f
INNER JOIN (
SELECT max(date) date, id
FROM foo
GROUP BY
id) lastF
ON f.id = lastF.id
and f.date = lastF.Date
或者真的很奇怪(不确定我是否正确得到了parens但它应该是一个LEFT连接到表栏但是bar需要内部连接到baz)
FROM
foo f
LEFT JOIN (bar b
INNER JOIN baz b2
ON b.id = b2.id
)ON f.id = b.id
答案 3 :(得分:1)
我更喜欢FROM子句,如果没有其他原因它只是在外键关系之间和逻辑限制之间区分过滤结果(来自笛卡尔积)。例如:
SELECT * FROM Products P JOIN ProductPricing PP ON P.Id = PP.ProductId
WHERE PP.Price > 10
与
相反SELECT * FROM Products P, ProductPricing PP
WHERE P.Id = PP.ProductID AND Price > 10
我可以看一下第一个,并立即知道我所放置的唯一逻辑限制是价格,而不是在关系键上连接表的隐式机制。
答案 4 :(得分:0)
您应该在Join子句中加入连接,这意味着From子句。关于在哪里放置过滤语句可能会有一个不同的问题。
关于缩进,有很多款式。我的偏好是缩进相关联接并保持主要条款,如Select,From,Where,Group By,Having和Order By缩进到同一级别。另外,我将每个主要属性和On子句的第一行放在它自己的行上。
Select ..
From Table1
Join Table2
On Table2.FK = Table1.PK
And Table2.OtherCol = '12345'
And Table2.OtherCol2 = 9876
Left Join (Table3
Join Table4
On Table4.FK = Table3.PK)
On Table3.FK = Table2.PK
Where ...
Group By ...
Having ...
Order By ...
答案 5 :(得分:0)
使用FROM子句符合ANSI-92标准。
此:
select *
from a
inner join b
on a.id = b.id
where a.SomeColumn = 'x'
不是这个:
select *
from a, b
where a.id = b.id
and a.SomeColumn = 'x'
答案 6 :(得分:0)
我总是在我的FROM子句中做我的JOINS(无论什么类型)。
我缩进他们的方式是:
SELECT fields
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.t1_id
INNER JOIN table3 t3 ON t1.id = t3.t1_id
AND
t2.id = t3.t2_id
实际上,我通常会更进一步,将我的约束逻辑从WHERE子句移动到FROM子句,因为这(至少在MS SQL中)前加载约束,这意味着它减少了查询结构中记录集的大小越早(我看到的文档与此相矛盾,但是当我这样做时,我的执行计划总是更有效率。)
例如,如果我只想在上面的查询中选择t3.id = 3的东西,你可以在WHERE子句中进行选择,或者你可以这样做:
SELECT fields
FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.t1_id
INNER JOIN table3 t3 ON t1.id = t3.t1_id
AND
t2.id = t3.t2_id
AND
t3.id = 3
我个人认为以这种方式提出的查询是非常易读和可维护的,但这肯定是个人偏好的问题,所以YMMV。
无论如何,我希望这会有所帮助。
答案 7 :(得分:0)
ANSI加入。我省略了SQL中的任何可选关键字,因为它们只会在等式中添加噪声。没有左内部加入,是吗?默认情况下,简单连接是一个内部连接,所以没有特别要说“内连接”。
然后我尽可能地对齐事物。
关键是大型复杂的SQL查询很难理解,因此为了使其更具可读性而对其施加的顺序越多越好。任何查看查询以修复,修改或调整它的人都需要能够立即回答一些问题:
我喜欢写我的查询,所以它们看起来像这样:
select PatientID = rpt.ipatientid ,
EventDate = d.dEvent ,
Side = d.cSide ,
OutsideHistoryDate = convert(nchar, d.devent,112) ,
Outcome = p.cOvrClass ,
ProcedureType = cat.ctype ,
ProcedureCategoryMajor = cat.cmajor ,
ProcedureCategoryMinor = cat.cminor
from dbo.procrpt rpt
join dbo.procd d on d.iprocrptid = rpt.iprocrptid
join dbo.proclu lu on lu.iprocluid = d.iprocluid
join dbo.pathlgy p on p.iProcID = d.iprocid
left join dbo.proccat cat on cat.iproccatid = lu.iproccatid
where procrpt.ipatientid = @iPatientID