在什么条件下这两个SQL查询会给出不同的结果?

时间:2014-10-19 15:39:05

标签: sql sql-server

免责声明:我通过在线教程帮助一个人学习SQL。所以你可以把它当作一个家庭作业问题。

我们在这里处理3个SQL Server表:

  • 船舶(名称,类别)
  • 班级 - 船舶(班级)的不同类别
  • 结果 - 该船发生了什么事(船舶,结果)

现在数据库的布局中有几个疯狂的东西,最大的一个是当Outcomes表中的船只以同样的方式命名时,它们可能不会出现在Ships表中作为Class中的课程。

重点是获得每个级别的沉船数量。我帮助学生学习了以下SQL:

Select 
    dbo.Classes.[class], Count(dbo.Outcomes.ship) as [count] 
from
    dbo.Classes
left join 
    dbo.Ships on dbo.Ships.[class] = dbo.Classes.[class]
left join 
    dbo.Outcomes on (dbo.Outcomes.ship = dbo.Classes.[class] or 
                     dbo.Outcomes.ship = dbo.Ships.name)
                 and dbo.Outcomes.result = 'sunk'
Group by 
    dbo.Classes.[class]

然而,显然,它是不正确的解决方案,因为在某些情况下它可能会返回不正确的结果。在网络上,我设法找到了本教程的以下解决方案:

select 
    classes.class, count(T.ship) 
from 
    classes
left join
    (select 
         ship, class 
     from 
         outcomes
     left join 
         ships on ship = name 
     where 
         result = 'sunk'
     union
     select 
         ship, class 
     from 
         outcomes
     left join 
         classes on ship = class 
     where 
         result = 'sunk') as T on classes.class = T.class
group by 
    classes.class

但我无法理解结果会在哪些条件下有所不同。使用两个不同的连接路径的Union操作是否与连接条件下的OR功能完全相同?

P.S。本教程中的这个特定问题实际上标记为2,难度为1-5。所以我觉得自己很蠢。

3 个答案:

答案 0 :(得分:3)

在许多情况下,查询可能会返回不同的结果。一个明显的例子是沉船与class中的nameoutcomes相匹配。在这种情况下,第二个查询中的union将返回一行。第一个查询中的join将返回两行。因此,计数会有所不同。

我认为您可以在第一个查询中使用count(distinct)来修复此特定问题。

答案 1 :(得分:3)

使用此数据集:

with Ships as (
    select * from (values
         ('HMS Prince of Wales','King George V')
        ,('King George V','King George V')
    )Ships(name,class)
),
Classes as (
    select * from (values
         ('King George V')
    )Classes(class)
),
Outcomes as (
    select * from (values
         ('HMS Prince of Wales','sunk')
        ,('King George V','sunk')
    )Outcomes(ship,result)
)

您提供的两个查询分别为:

class         count
------------- -----------
King George V 3

class         
------------- -----------
King George V 2

区别的原因是 UNION 是一个集合运算符,可以消除重复项(与 UNION ALL 不同),而 OR 运算符不会吨。我们可以通过用UNION ALL替换第二个查询中的UNION来测试这个,现在产生:

class         
------------- -----------
King George V 3

就像你提出的第一个解决方案一样。

答案 2 :(得分:1)

需要的目标: "重点是获得每个级别的沉船数量。我帮助学生学习了以下SQL:"

应该分三个步骤创建Sudo代码。你需要将它们分解为工作步骤

select * from class 
//create a list of all of the classes that exists in your db

select * from [working previous statement] where results = "sunk"
//create another select statement that uses the previous select statement to refine  results
//then refine it to have ships that have been sunk

select count from [[previous statement with the two selects]]
//This create the count of all of the sunk ships.

select count from [[previous statement with the two selects]] group by [previous statement with one select]
//this one should create the individual count of all of the sunken ships based on it's class

select sum from [[your pick of which statement]]
//do a sum

自然你需要进行链接,所以代码应该实现为 从船舶sh,类别cl,结果oc选择船舶,其中sh.class = cl.class和oc.ship = sh.ship和oc.result = sunk group by cl.classes

然后在混合中添加计数步骤。