Алгоритм контроля версий - PullRequest
3 голосов
/ 02 декабря 2008

У меня есть база данных, где я храню объекты. У меня есть следующая (упрощенная) схема

CREATE TABLE MyObjects
(
  UniqueIdentifier Id;
  BigInt           GenerationId;
  BigInt           Value;
  Bit              DeleteAction;
)

Каждый объект имеет уникальный идентификатор («Id») и свойство (набор) («Значение»). Каждый раз, когда значение свойства объекта изменяется, я вношу в эту таблицу новую строку с идентификатором нового поколения («GenerationId», который монотонно увеличивается). Если объект удален, я записываю этот факт, устанавливая бит «DeleteAction» в true.

В любой момент времени (генерация) я хотел бы получить состояние всех моих активных объектов!

Вот пример:

Id    GenerationId Value  DeleteAction
1        1          99       false
2        1          88       false
1        2          77       false
2        3          88       true

Объектами в поколениях являются:

  1: 1 {99}, 2 {88}
  2: 1 {77}, 2 {88}
  3: 1 {77}

Ключ: как я могу узнать строку для каждого уникального объекта, чей идентификатор поколения ближе всего (но не превышает) к данному идентификатору поколения ? Затем я могу выполнить шаг после фильтрации, чтобы удалить все строки, для которых поле DeleteAction имеет значение true.

Ответы [ 4 ]

4 голосов
/ 02 декабря 2008

Это работает в MS SQL

SELECT id,value
FROM Myobjects
INNER JOIN ( 
     SELECT id, max(GenerationID) as LastGen 
     FROM MyObjects
     WHERE GenerationID <= @Wantedgeneration
     Group by ID)
    On GenerationID = LastGen
WHERE DelectedAction = false
2 голосов
/ 02 декабря 2008

Моя версия использует соединение таблицы MyObjects против подмножество самого себя, созданное подзапросом и содержащее только последний генерация для каждого объекта:

SELECT O.id,generation,value FROM 
     MyObjects O, 
     (SELECT id,max(generation) AS max_generation FROM MyObjects 
     WHERE generation <= $GENERATION_ID GROUP BY id) AS TheMax WHERE 
            TheMax.max_generation = generation AND O.deleted is False
     ORDER BY generation DESC;

В приведенном выше запросе GENERATION_ID является аппаратным. Способ параметризовать это написать функцию:

CREATE OR REPLACE FUNCTION generation_objects(INTEGER) RETURNS SETOF MyObjects AS
  'SELECT O.id,generation,value,deleted FROM 
       MyObjects O, 
       (SELECT id,max(generation) AS max_generation FROM MyObjects 
       WHERE generation <= $1 GROUP BY id) AS TheMax WHERE 
              TheMax.max_generation = generation AND O.deleted is False;'
  LANGUAGE SQL;

Теперь это работает. С этой таблицей:

> SELECT * FROM MyObjects;          
 id | generation | value | deleted 
----+------------+-------+---------
  1 |          1 |    99 | f
  2 |          2 |    88 | f
  1 |          3 |    77 | f
  2 |          4 |    88 | t
  3 |          5 |    33 | f
  4 |          6 |    22 | f
  3 |          7 |    11 | f
  2 |          8 |    11 | f

Я получаю:

> SELECT * FROM generation_objects(1) ORDER by generation DESC;
 id | generation | value | deleted 
----+------------+-------+---------
  1 |          1 |    99 | f

> SELECT * FROM generation_objects(2) ORDER by generation DESC;
 id | generation | value | deleted 
----+------------+-------+---------
  2 |          2 |    88 | f
  1 |          1 |    99 | f

> SELECT * FROM generation_objects(3) ORDER by generation DESC;
 id | generation | value | deleted 
----+------------+-------+---------
  1 |          3 |    77 | f
  2 |          2 |    88 | f

И затем при следующем поколении объект 2 удаляется:

> SELECT * FROM generation_objects(4) ORDER by generation DESC;
 id | generation | value | deleted 
----+------------+-------+---------
  1 |          3 |    77 | f
1 голос
/ 06 декабря 2008

Вот рабочая версия:

SELECT MyObjects.Id,Value
FROM Myobjects
INNER JOIN 
(      
  SELECT Id, max(GenerationId) as LastGen
  FROM MyObjects
  WHERE GenerationId <= @TargetGeneration
  Group by Id
) T1
ON MyObjects.Id = T1.Id AND MyObjects.GenerationId = LastGen
WHERE DeleteAction = 'False'
0 голосов
/ 02 декабря 2008

Не уверен, что это стандартный SQL, но в Postgres вы можете использовать флаг LIMIT:

 select GenerationId,Value,DeleteAction from MyObjects 
    where Id=1 and GenerationId < 3 
    order by GenerationId
    limit 1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...