设计具有多个连接的查询的正确“方向”是什么?

时间:2018-04-18 06:13:08

标签: sql oracle

获取信息'A'您想从数据库中获取信息'E'。它们之间没有直接连接,因此您必须选择使用多个表。例如,您可以使用INNER JOIN来实现此目的。

我的问题

您是否选择目标信息'E'开始写'反向'...

SELECT 
    E.myTargetColumn
FROM 
    TblE E
INNER JOIN TblD D ON 1=1
INNER JOIN TblC C ON 1=1
INNER JOIN TblB B ON 1=1
INNER JOIN TblA A ON 1=1
WHERE 
    A.ID = myKnownInformation

...或者您选择以您已有的信息'A'开头?

SELECT 
    E.myTargetColumn
FROM 
    TblA A
INNER JOIN TblB B ON 1=1
INNER JOIN TblC C ON 1=1
INNER JOIN TblD D ON 1=1
INNER JOIN TblE E ON 1=1
WHERE 
    A.ID = myKnownInformation

两种设计都对我有意义。版本1,因为您直接选择所需的列。我不喜欢的是,你必须反思。

I need this Information, what do i need for that.

第二个版本对我来说也很有意义;您从所拥有的信息开始。我不喜欢它;您必须等到写入最后一个Join才能真正知道目标列的别名(E.myTargetColumn)。

I have this information, how do i reach my target information?

1。这是什么标准?
 2.两种设计的优缺点是什么?

补充问题;什么是JOIN的标准缩进?

3 个答案:

答案 0 :(得分:3)

优化器并不关心,因为它会决定连接顺序本身,但为了便于阅读,我总是会从我的工作向前工作而不是向后工作。

select e.mytargetcolumn
from   tbla a
       join tblb b
            on  b.somekey = a.somekey
       join tblc c
            on  c.somekey = b.somekey
       join tbld d
            on  d.somekey = c.somekey
       join tble e
            on  e.somekey = d.somekey
where  a.id = myknowninformation

(这适用于内部联接。如果涉及外部联接,则联接顺序开始产生差异。)

这也适用于单个谓词,即使SQL解析器不关心 - 它是b.somekey = a.somekey而不是a.somekey = b.somekey,因为我们指定了b的条件,与b.job = 'MINION'b.middle_name is null。有关此问题的讨论,请参阅https://jonathanlewis.wordpress.com/2006/11/02/clarity-clarity-clarity及其评论。

至少在Oracle中,innerouter关键字是可选的,不会添加任何信息,所以我认为它们是多余的,从不使用它们。

答案 1 :(得分:1)

决定在左连接上保留哪个表取决于您想要实现的目标。当table1中的连接条件的唯一值的数量与table2不同时,通常使用左连接。

例如 的表1:

| id | name|
+----+------+
| 1  | John |
| 2  | Bob  |
| 3  | Brian|

<强>表2:

| id | subject| marks|
+----+------+------+
| 1  | History| 15   |
| 2  | Maths  | 22   |
| 2  | History| 17   |

我会这样做

select Table1.name, sum(table2.marks) as total_marks --you will need to handle the null though
from table1
left join table2
  on table1.id = table2.id
group by Table1.name;

基本上,包含所有行的表将首先位于不包含所有行的表的位置。

如果值的数量相同,那么您应该使用内部联接,顺序无关紧要。通常人们倾向于在开始时保持表中行数最多的表,否则将基表的类别保留在开头(即你的第二个例子),但这取决于你。

格式化是主观的,但根据我的经验,我将代码保持在同一级别,并在连接条件中略微缩进。例如

select a.column1 ,a.column2 ,a.column3 ,a.column4
                ,a.column5 , table1.column6  -- I indent this and add to the next line if there are lots of select items
      -- I also keep the comma just before the column name so that if I want to comment it out the SQL code does not throw an error due to an extra comma in the previous line
from table1 --Same line because it is just one table
inner join 
(
    --Everything in here will be indented because it is an inner query 
    select * from    --from is in the same line to save space, if there were selected columns it would be in the next line
    table 2
    where id = 1
) a
   on  table1.id = a.id    --I like to indent the on criteria as it helps differentiate between tables, especially in a code like the one that you posted
            and table1.name = a.name    --multiple join criteria is just like multiple select columns
where tabl1.name = "Bob"

答案 2 :(得分:1)

您的查询都不比其他查询好。只需选择你喜欢的任何一个。

然而,仅仅考虑加入是一个常见的错误。加入,当您想要加入信息时。我们来看一个例子:

select p.product_name
from product p
join product_order po on po.product_id = p.product_id
where po.order_date > date '2017-04-01';

我们希望看到2017年4月1日之后订购的产品。但是,如果从那时起多次订购产品怎么办?然后我们会得到相同的产品多重。一个典型的“解决方案”是将其更改为select distinct p.product_name,但是从一开始就只选择一个产品会更好。查询应该使用EXISTSIN

完成
select product_name
from product
where product_id in 
  (select product_id from product_order where po.order_date > date '2017-04-01');

现在我们可以争辩你的查询最好是:

select mytargetcolumn
from e
where key1 in
  (select key2 from d where key3 in
    (select key4 from c where key5 in
      (select key6 from b where key7 in
        (select key8 from a where key9 = myKnownInformation)
      )
    )
  )

在这个小例子中,这甚至是可读的。但在更复杂的情况下,所有这些子查询可能会令人困惑。另一种选择是:

select mytargetcolumn
from e
where key1 in
(
  select d.key2
  from d
  join c on d.key3 = c.key4
  join b on c.key5 = b.key6
  join a on b.key7 = a.key8
  where a.key9 = myKnownInformation
);

这两个查询中没有一个真的比其他查询“更好”。 (对于第二个查询,我们再次遇到表格顺序的“问题”,并想知道a.key9 = myKnownInformationwhere中是否应该on。)

所有这些实际上归结为:尽可能地将您的查询编写为可读。如果您认为from子句中的某个顺序比另一个更可读,那么请使用它。但请记住:也许你甚至不想加入: - )