SQL - 四个表之间的查询

时间:2016-03-17 17:27:49

标签: sql sql-server database relational-database

我的查询有问题。

select  p.id, p.firstname, p.lastname , max(s.year) as 'Last Year', min(s.year) as 'First Year', c.name from pilot p
join country on country.sigla = p.country
join circuit c on c.country_id = country.sigla
join season s
on(p.id = s.pilot_id)
group by p.id, p.firstname, p.lastname, c.name
order by p.id

表Pilot

Id (Primary Key)
Name
Table Season

表季

Year (Primary key)
Pilot_id (Foreign Key)

表国家/地区

Sigla (Primary Key)

表Cicuit

id (Primary Key)
name

Pilot表与季节和国家相关联。表格电路与国家相关联。 我想为每个飞行员显示每一行中的最后一个和第一个电路,但问题是我有重复的结果。第一个结果显示我第一个电路,副本显示我的最后一个电路。我有67个结果,我想只有40个(数据库中的飞行员总数)

3 个答案:

答案 0 :(得分:0)

根据您的表格使用内嵌sql,如此编辑的

SELECT *
FROM (
    SELECT p.id
        ,p.firstname
        ,p.lastname
        ,FirstCircuit = (
            SELECT TOP 1 circuitname
            FROM circuit c
            WHERE p.id = c.id
            ORDER BY year ASC
            )
        ,LastCircuit = (
            SELECT TOP 1 circuitname
            FROM circuit c
            WHERE p.id = c.id
            ORDER BY year DESC
            )
    FROM pilot p
    INNER JOIN country ON country.sigla = p.country
    INNER JOIN season s ON (p.id = s.pilot_id)
    ) tbl
GROUP BY id
    ,firstname
    ,lastname
ORDER BY id

答案 1 :(得分:0)

从上面借来的答案进一步解释,因为我无法评论它。 您需要编写第一年和去年的子查询,以便为每个子查询使用不同的选择条件。第一年,您希望按年份ASC订购,以获得该列中最小的一年。对于去年,您需要按年份DESC订购才能获得该栏目中最大的一年。

SELECT *
FROM (
    SELECT p.id
        ,p.firstname
        ,p.lastname
        ,FirstCircuit = (
            SELECT TOP 1 circuitname
            FROM circuit c
            WHERE p.id = c.id
            ORDER BY year ASC
            )
        ,LastCircuit = (
            SELECT TOP 1 circuitname
            FROM circuit c
            WHERE p.id = c.id
            ORDER BY year DESC
            )
    FROM pilot p
    INNER JOIN country ON country.sigla = p.country
    INNER JOIN season s ON (p.id = s.pilot_id)
    ) tbl
GROUP BY id
    ,firstname
    ,lastname
ORDER BY id

答案 2 :(得分:0)

我怀疑问题在于加入circuit表。

无需替换选择列表中的MIN(s.year)MAX(s.year)表达式。 (尽管其他答案建议,但没有解决实际问题...获得符合规范的结果,每个飞行员只返回一个行。)

从更简单的查询开始调试...只加入pilot表和season表。例如:

 select p.id
      , p.firstname
      , p.lastname
      , max(s.year) as 'Last Year'
      , min(s.year) as 'First Year'
   from pilot p
   join season s
     on p.id = s.pilot_id
  group by p.id, p.firstname, p.lastname
  order by p.id

pilot最多应返回一行(假设id表中pilot是唯一的。)pilot中没有的行由于内部联接,season中的任何关联行都将被排除。

当您将连接添加到其他表(countrycircuit)时,您可能会引入重复的行。但是这些行将被“折叠”为每个飞行员的一行。

当您在c.name中加入GROUP BY时,就会在您的“重复”行开始出现在结果集中。使用GROUP BY子句中的表达式,您可以为每个飞行员返回多行。

这就是问题所在。

我们保证每位飞行员返回的行都会有c.name的不同值。

要解决此问题,您可以从c.name子句中删除GROUP BY,并在选择列表中使用聚合表达式,例如MAX(c.name)

该查询将返回(最多)每个飞行员一行。 (同样,如果circuit中没有与与导频关联的country相关联的行,则会排除这些导频行。)

 select p.id
      , p.firstname
      , p.lastname
      , max(s.year) as 'Last Year'
      , min(s.year) as 'First Year'
      , max(c.name) as circuit_name
   from pilot p
   join season s
     on p.id = s.pilot_id
   join country 
     on country.sigla = p.country
   join circuit c
     on c.country_id = country.sigla
  group by p.id, p.firstname, p.lastname
  order by p.id

关于返回“每行上的第一个和最后一个电路”的一点......

如何确定哪个电路是“第一个”,哪个电路是“最后一个”?我们在表格中看到的只有两列是idnamepilotcircuit之间的唯一关系(显示)是通过country表。 pilot只有一个country,因此导频与country中的每个电路相关联。