SQL-запрос, чтобы показать отличие от той же таблицы - PullRequest
3 голосов
/ 22 февраля 2010

В моем приложении есть таблица, которая содержит данные инвентаризации снимков за каждый год. Например, есть таблица инвентаризации транспортных средств с типичными столбцами 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

(Хорошо это или плохо, эта таблица уже существует, и ее нельзя изменить, и это тема для другого вопроса). То, что вы видите здесь, год за годом, большинство транспортных средств все еще находятся в инвентаре, но всегда есть ситуация, когда от старых избавляются и приобретаются новые транспортные средства. В приведенном выше примере Nissan Altima 1995 года находился в инвентаре 2009 года, но больше не в инвентаре 2010 года. У инвентаря 2010 есть новый Ford Explorer 2010 года.

Как мне создать эффективный запрос, который занимает любые два года и показывает только разницу. Например, если я передам в 2009, 2010, запрос должен вернуть

3   CCC777  1995  Nissan  Altima      white   2009

Если я укажу в 2010, 2009, запрос должен вернуть

6   DDD888   2010  Ford   Explorer   white   2010

Edit: Я должен был добавить комментарий после ответа от Кайла Б., но текстовая область для комментария не очень удобна для пользователя:

Я не думал, что это будет так сложно, но, похоже, это так.

В любом случае, вам не понадобится дополнительный выбор из приведенного выше:

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 ]

5 голосов
/ 22 февраля 2010

Вы хотите само-внешнее объединение

Похоже, вы хотите асимметричную разницу. Если вы хотите получить симметричное различие, вы бы использовали полное внешнее соединение вместо левого (или правого) внешнего соединения.

С переменными: первый год и: второй год

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.

0 голосов
/ 23 февраля 2010

Я думаю, что Кайл Батт дал почти идеальный ответ. Он получил меня на 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+ записей.
0 голосов
/ 23 февраля 2010

Я не уверен, насколько «эффективной» будет эта идея; однако вы, вероятно, можете использовать оператор SQL EXCEPT. Просто пример, он не вернет всю нужную вам строку, однако вы получите идею:

select plate, name from inventory where year_owned=2009
except
select plate, name from inventory where year_owned=2010
0 голосов
/ 22 февраля 2010

В этом запросе будут выбраны все автомобили 2010 года, которых не было в таблице в предыдущие годы.

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

Используя эту структуру, должно быть очевидно, как ее переставить, чтобы производить автомобили, которые больше не существуютсуществует в 2010 году.

0 голосов
/ 22 февраля 2010
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=___;

Редактировать: ой, я неправильно понял. Как мне удалить мой ответ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...