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查询:使用内连接查询两张表的时候,如果左边表的一条记录对应了右边表的两条记录,结果显示排列问题