Выберите несколько строк по максимуму - PullRequest
1 голос
/ 03 октября 2011

У меня есть простая таблица со схемой «версий»:

Version | PartKey1 | PartKey2 | Value
   1    |    0     |    0     | foo
   2    |    0     |    0     | bar
   1    |    1     |    0     | foobar

Эта таблица средняя (~ 100 000 строк для полной версии). В начале он загружается с версией 1, которая содержит полный снимок, и с течением времени добавляются инкрементные обновления, но мы хотим сохранить старые версии, поэтому они добавляются с увеличенным номером «Версия» (2 здесь). 1004 *

При чтении данных я хочу иметь возможность указать максимальную версию, и я хотел бы, если возможно, получить только те «строки», которые меня интересуют.

Например: указав 2 в качестве максимальной версии, я бы хотел запрос, который извлекает только 2 строки в таблице выше:

Version | PartKey1 | PartKey2 | Value
   2    |    0     |    0     | bar
   1    |    1     |    0     | foobar

Строка:

   1    |    0     |    0     | foo

отбрасывается, потому что версия 2 этой строки является более новой.

Мне было интересно, был ли такой выбор возможен / целесообразен в запросе SQL. Я могу выполнить фильтрацию на стороне приложения, но, очевидно, это означает получение бесполезных ресурсов из БД, поэтому, если это возможно (и дешево на стороне БД), я бы предпочел переложить эту работу на БД.

Ответы [ 3 ]

5 голосов
/ 03 октября 2011

Вы можете сделать:

SELECT v1.*
  FROM versioningscheme v1
  LEFT JOIN versioningscheme v2
    ON v2.partkey1 = v1.partkey1 AND v2.partkey2 = v1.partkey2
   AND v2.version > v1.version
 WHERE v2.version IS NULL

Левое соединение с обнаружением NULL очень мощное и недостаточно используется. Нулевые значения возвращаются, когда нет совпадения (и, очевидно, когда у вас есть максимальная строка в v1, вы не можете получить строку в v2, которая удовлетворяет условию соединения).

2 голосов
/ 03 октября 2011

Это обычное явление для данных, изменяющихся во времени (когда вы решаете найти самое последнее значение в определенном окне времени), и вполне разумно.

В вашем случае ROW_NUMBER () позволяет анализировать данные только один раз, а не несколько раз. С соответствующим ИНДЕКСОМ, таким как (PartKey1, PartKey2, Version), это должно быть исключительно быстрым ...

SELECT
  *
FROM
(
  SELECT
    *,
    ROW_NUMBER() OVER (PARTITION BY PartKey1, PartKey2 ORDER BY Version DESC) AS reversed_version
  FROM
    MyTable
  WHERE
    Version <= <MaxVersionParamter>
)
  AS data
WHERE
  reversed_version = 1
2 голосов
/ 03 октября 2011
select t.*
from MyTable t
inner join (
    select PartKey1, PartKey2, max(Version) as MaxVersion
    from MyTable
    where Version <= 2
    group by PartKey1, PartKey2
) tm on t.PartKey1 = tm.PartKey1 
    and t.PartKey2 = tm.PartKey2 
    and t.Version = tm.MaxVersion
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...