Обнаружение изменений между строками с одинаковым идентификатором - PullRequest
3 голосов
/ 22 марта 2010

У меня есть таблица, содержащая некоторые имена и связанный с ними идентификатор вместе со снимком:

snapshot, systemid, name[, some, other, columns]

Мне нужно идентифицировать все уникальные name, которые systemid имели во всех моментальных снимках, но только там, где произошло хотя бы одно изменение.

Например, с данными:

'DR1', 0, 'MOUSE_SPEED'
'DR1', 1, 'MOUSE_POS'
'DV8', 0, 'MOUSE_BUTTONS'
'DV8', 1, 'MOUSE_POS'
'DR6', 0, 'MOUSE_BUTTONS'
'DR6', 1, 'MOUSE_POS'
'PP2', 0, 'MOUSE_SPEED'
'PP2', 1, 'MOUSE_POS'

... Я хотел бы запрос, который будет возвращать (в любом порядке):

0, 'MOUSE_SPEED'
0, 'MOUSE_BUTTONS'

Кроме того, было бы полезно иметь инверсию - список systemid с, который оставался стабильным в течение всех snapshot с (то есть, когда name никогда не менялся) .

Я использую PostgreSQL v8.4.2.

РЕДАКТИРОВАТЬ: Обновлено для отражения комментариев (извините за оригинальный не идеальный пост, я новичок здесь!) .

Ответы [ 4 ]

0 голосов
/ 23 марта 2010

Для измененных:

SELECT t1.snapshot, t1.systemid
FROM table t1
GROUP BY t1.snapshot, t1.systemid
HAVING min(t1.name) <> max(t1.name)

даст вам снимок и идентификатор тех, которые изменились

Для тех, кто остался прежним

SELECT t1.snapshot, t1.systemid
FROM table t1
GROUP BY t1.snapshot, t1.systemid
HAVING min(t1.name) = max(t1.name)

Присоединение значений к первому или последнему запросу можно выполнить с помощью присоединенного подзапроса или коррелированного подзапроса

Регистрация (пример с измененными именами)

SELECT t2.snapshot, t2.systemid, t2.name
FROM table t2
     JOIN (
           SELECT snapshot, systemid
           FROM table 
           GROUP BY snapshot, systemid
           HAVING min(name) <> max(name) ) t1
     ON t2.snapshot = t1.snapshot AND t2.systemid = t1.systemid

Соотнесено (пример с именами, которые остались прежними)

SELECT t2.snapshot, t2.systemid, t2.name
FROM table t2
WHERE t2.name IN (
           SELECT t1.name
           FROM table t1
           WHERE t2.snapshot = t1.snapshot AND t2.systemid = t1.systemid
           GROUP BY t1.name
           HAVING COUNT(DISTINCT t1.name) = 1 ) 

Если вам не нужен снимок для обратного запроса, тогда

SELECT DISTINCT t2.systemid, t2.name

и отдыхай так же.

Запросы не проверены, но я надеюсь, что подходы понятны

0 голосов
/ 22 марта 2010

Следующее относится к SQL Server, но не использует какие-либо специфические конструкции SQL Server. Он должен быть переносимым на postgresql.

Оператор SQL

SELECT  DISTINCT t1.id, t1.name
FROM    @Table t1
        INNER JOIN (
          SELECT  t.id 
          FROM    (
                    SELECT  DISTINCT id, name
                    FROM    @Table
                  ) t
          GROUP BY t.id 
          HAVING COUNT(*) > 1
        ) t2 ON t2.id = t1.id

Данные испытаний

DECLARE @Table TABLE (snapshot INTEGER, id INTEGER, name VARCHAR(32))

INSERT INTO @TABLE
SELECT 1, 0, 'MOUSE_SPEED'
UNION ALL SELECT 1, 1, 'MOUSE_POS'
UNION ALL SELECT 1, 2, 'KEYBOARD_STATE'
UNION ALL SELECT 2, 0, 'MOUSE_BUTTONS'
UNION ALL SELECT 2, 1, 'MOUSE_POS'
UNION ALL SELECT 2, 2, 'KEYBOARD_STATE'
UNION ALL SELECT 3, 0, 'MOUSE_SPEED'
UNION ALL SELECT 3, 1, 'MOUSE_POS'
UNION ALL SELECT 3, 2, 'KEYBOARD_STATE'
0 голосов
/ 22 марта 2010
select distinct s1.snapshot, s1.id, s1.name from snapshot s1, snapshot s2   
where s1.snapshot != s2.snapshot   
and s1.id = s2.id   
and s1.name != s2.name
0 голосов
/ 22 марта 2010

В PostgreSQL есть оператор EXCEPT, который, как я помню, почти такой же, как MINUS (например, в Oracle), так что, может быть, что-то подобное будет работать?

select id, name
from some_table
where snapshot = '1' and id in ('1', '2', '0')
except
select id, name
from some_table
where snapshot = '2' and id in ('1', '2', '0')

Если у вас есть несколько shapshots, вы можете попробовать объединить их все в одну длинную последовательность EXCEPT s, или вы можете написать процедуру для их итеративной обработки, такую ​​как (псевдокод):

for i = 1 to maX(snapshot)-1 loop
    results := diff_query(i, i+1)  //the query above, but inside a procedure or something
    forall records in results loop
        /* do your processing  here */
    end loop
end loop

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

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