SQL查询显示来自同一个表的差异

时间:2010-02-22 17:31:56

标签: sql join

我的应用程序有一个表,其中包含每年的快照库存数据。例如,车辆库存表中包含典型列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年日产Altima在2009年的库存中,但不再是2010年的库存。 2010年的库存有一个新的2010福特Explorer。

如何构建一个有效查询,需要两年时间才能显示差异。例如,如果我在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

5 个答案:

答案 0 :(得分:5)

您需要自我加入

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

使用变量:第一年和第二年

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测试。

答案 1 :(得分:0)

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=___;
编辑:哎呀,我误解了。如何删除我的答案?

答案 2 :(得分:0)

此查询将选择2010年中表中不存在的所有汽车。

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

使用这种结构,应该很明显如何重新排列它以生产2010年不再存在的汽车。

答案 3 :(得分:0)

我不确定这个想法会有多么'有效';但是你可以使用'EXCEPT'SQL语句。只是一个示例,这不会返回您想要的完整行,但是您会得到这个想法:

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

答案 4 :(得分:0)

我认为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
  1. 请注意子查询
  2. 运行速度相当快,超过100,000条记录。