【问题标题】:SQL - Query between four tablesSQL - 四个表之间的查询
【发布时间】:2016-03-17 17:27:48
【问题描述】:

我的查询有问题。

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

表试点

Id (Primary Key)
Name
Table Season

餐桌季节

Year (Primary key)
Pilot_id (Foreign Key)

餐桌国家

Sigla (Primary Key)

表电路

id (Primary Key)
name

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

【问题讨论】:

  • 谁是“e”? (e.year)为什么需要你“季节”?从查询中删除“季节”。
  • 表定义不包括查询中引用的某些列,例如circuit.country_id,您将使用什么查询来查找给定飞行员的“第一”电路?还是找到“最后一个”电路?从显示的表定义中,区分它的唯一方法是使用id 列、name 列或两者的组合。似乎没有任何其他方式可以从circuit 对行进行排序。看起来飞行员最多与一个国家有关,因此飞行员与与同一国家相关的每个电路有关。你如何订购电路

标签: sql sql-server database relational-database


【解决方案1】:

从上面借来的答案和进一步的解释,因为我无法评论它。 您需要为第一年和最后一年编写子查询,以便为每个查询使用不同的选择标准。对于第一年,您想按年份 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

【讨论】:

  • 使用此查询模式,FirstCircuitLastCircuit 返回的值将是不确定的。通过对外部查询中的表的列引用进行排序(yearseason 表中)...每个year 都与每个circuit 相关联。子查询中的谓词看起来是错误的……circuit 表的id 值必须与pilot 表的id 值匹配。并且没有解释为什么我们要从每个country 中查询每个circuit,而不仅仅是与飞行员相关的country 相关的circuit
【解决方案2】:

使用像这样根据您的表编辑的内联 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

【讨论】:

  • 虽然此代码可能会回答问题,但提供有关 why 和/或 如何 此代码回答问题的附加上下文将显着改善其长期-期限价值。请edit你的答案添加一些解释。
【解决方案3】:

我怀疑问题出在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 最多应该返回一行(假设idpilot 表中是唯一的。)pilot 中的行在season 中没有任何关联的行将由于内部连接而被排除在外。

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

当您在GROUP BY 中包含c.name 时,您的“重复”行开始出现在您的结果集中。使用GROUP BY 子句中的该表达式,您有可能为每个飞行员获得不止一行。

这就是问题所在。

您将保证返回的行对于每个试点都有不同的 c.name 值。

要解决此问题,您可以从 GROUP BY 子句中删除 c.name,并在选择列表中使用聚合表达式,例如 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 中的每个电路相关联。

【讨论】:

    猜你喜欢
    • 2010-12-21
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多