SQL查询显示同一张表的差异

Posted

技术标签:

【中文标题】SQL查询显示同一张表的差异【英文标题】:SQL query to show difference from the same table 【发布时间】:2010-02-22 17:31:55 【问题描述】:

我的应用程序有一个表,其中包含每年的快照库存数据。例如,有一个车辆库存表,其中包含典型的列 vehicle_id、vehicle_plate_num、vehicle_year、vehicle_make 等,还有指定车辆拥有的年份。

查询整个表可能会导致如下结果:

Id  Plate Num   Year Make     Model    Color   Year Owned
---------------------------------------------------------
1   AAA555      2008 Toyota   Camry    blue    2009
2   BBB666      2007 Honda    Accord   black   2009
3   CCC777      1995 Nissan   Altima   white   2009
4   AAA555      2008 Toyota   Camry    blue    2010
5   BBB666      2007 Honda    Accord   black   2010
6   DDD888      2010 Ford     Explorer white   2010

(好或坏,这个表已经存在,重新设计表不是一个选项,这是另一个问题的主题)。你在这里看到的是年复一年,大部分车辆还在库存中,但总是出现旧车淘汰,新车收购的情况。在上面的示例中,1995 年的 Nissan Altima 在 2009 年的库存中,但不再在 2010 年的库存中。 2010 年库存有一个新的 2010 年福特探索者。

如何构建一个需要两年时间并且只显示差异的高效查询。比如我传入2009、2010,查询应该返回

3   CCC777  1995  Nissan  Altima      white   2009

如果我在 2010 年、2009 年通过,查询应该返回

6   DDD888   2010  Ford   Explorer   white   2010

编辑: 我应该在 Kyle B. 的回答之后添加评论,但评论的文本区域不是很人性化:

我没想到会这么难,但似乎是。

无论如何,您不需要像这样从上面的子选择中选择:

select q.* from (
    select f.*
    from inventory f 
      left join inventory s
      on (f.plate_num = s.plate_num 
         and f.year_owned = :first-year
         and s.year_owned = :second-year)
    where s.plate_num is null
) q
where q.year_owned = :second_year

【问题讨论】:

【参考方案1】:

您想要一个自外部联接

看起来你想要不对称的差异。如果您想要对称差异,您可以使用完全外连接而不是左(或右)外连接。

带有变量:第一年和:第二年

select f.*
   from inventory f 
     left join inventory s
        on (f.plate_num = s.plate_num
           and s.year_owned = :second-year)
where s.plate_num is null 
  and f.year_owned = :first-year

请注意,条件必须在连接条件内,以便数据库在没有匹配项时返回空行,而不是找到稍后通过过滤删除的匹配项。

编辑:略微调整查询。这不需要子选择。用 postgresql 测试。

【讨论】:

绝对是正确的想法。不过,应该将“f.year_owned”从“join”条件中移到“where”子句中。 范的权利。我需要将 f 的限定条件移出 join 子句。【参考方案2】:
select a.id, a.platenum, a.year, a.make, a.model, a.color, b.yearowned
from inventory a
join inventory b on a.platenum=b.platenum
where a.yearowned=___ and b.yearowned=___;

编辑:哎呀,我误会了。如何删除我的答案?

【讨论】:

【参考方案3】:

此查询将选择 2010 年的所有汽车,这些汽车在过去几年中不存在于表中。

select * 
from cars
where Year_Owned = 2010
  and plate not in (
        select plate 
        from cars 
        where year_owned < 2010);

使用这种结构,如何重新安排它以生产 2010 年不再存在的汽车应该是显而易见的。

【讨论】:

【参考方案4】:

我不确定这个想法会有多“有效”;但是您可能可以使用“EXCEPT”SQL 语句。只是一个示例,这不会返回您想要的完整行,但是您会明白的:

select plate, name from inventory where year_owned=2009
except
select plate, name from inventory where year_owned=2010

【讨论】:

【参考方案5】:

我认为 Kyle Butt 给出了几乎完美的答案。他让我成功了 90%。

答案如下:

查询所有在 2010 年但不在 2009 年库存中的车辆:

select q.* from (
    select f.* from inventory f 
        left join inventory s
        on (f.plate_num = s.plate_num 
            and f.year_owned = 2010
            and s.year_owned = 2009)
        where s.plate_num is null
    ) q
where q.year_owned = 2010

查询所有在 2009 年但不在 2010 年库存中的车辆:

select q.* from (
    select f.* from inventory f 
        left join inventory s
        on (f.plate_num = s.plate_num 
            and f.year_owned = 2009
            and s.year_owned = 2010)
        where s.plate_num is null
    ) q
where q.year_owned = 2009
    注意子查询 100,000 多条记录运行速度相当快。

【讨论】:

我调整了答案,你不需要子选择。 谢谢凯尔,我更喜欢你新调整的查询(没有子查询)。我测试过,它也适用于 SQL Server。

以上是关于SQL查询显示同一张表的差异的主要内容,如果未能解决你的问题,请参考以下文章

sql查询:使用内连接查询两张表的时候,如果左边表的一条记录对应了右边表的两条记录,结果显示排列问题

SQL一次性查询一个字段不同条件下的统计结果(另一张表的统计数量)

同一张表省市县sql查询

SQL 两张表合并 (两张表的列都相同)

如何用SQL语句查询两张表中的相同字段数据

sql如何查询出一张表的的某个字段数据更换成另一张表的字段数据