2010-03-22 6 views
3

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

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

мне нужно определить все уникальные name s, что 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 s, которые остались стабильными через всеsnapshot s (то есть, где name никогда не изменялся).

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

EDIT:Обновлено чтобы отразить комментарии (извините за оригинал менее чем совершенный пост, я здесь новенький!).

+2

что бы вы перечислить вам, когда, если изменения в снимок 3? – Unreason

+2

Если значения моментального снимка нельзя упорядочить (напрямую или через другое поле), вы не можете отличить 2, 0, «MOUSE_BUTTONS» и 3, 0, «MOUSE_BUTTONS» от данных образца. Вас интересует, какой из них выбран? Если да, то как вы выбрали его для примера результатов? – Unreason

+0

Я предлагаю вам предоставить нам реальные данные. Мы не против помогать, но, оставляя много, чтобы быть угаданными или предоставляющими неправильные исходные данные, просто пустая трата вашего и нашего времени. Учитывая, что вы новичок в SO, я уверен, что все понимают, но воспринимают это как хороший совет для будущих вопросов. –

ответ

0

Ниже приведен 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

К сожалению, поле моментального снимка представляет собой строку, такую ​​как «PP16», «PP16B», «DS21». Их не гарантировано - я не возражаю против того, какие изменения были сделаны, только они были сделаны и снимки, где они были изменены. – Noah

+1

@Noah, если вы не можете установить порядок снимков из его значения, то вы не можете установить, в котором он изменился. Например, если PP16 является MOUSE_POS, PP16B является MOUSE_POS, а DS21 - MOUSE_BUTTONS, тогда вы не можете заключить, в какой из них он изменился. Я могу утверждать, что он изменился с MOUSE_POS на MOUSE_BUTTONS обратно на MOUSE_POS, но в равной степени я могу утверждать, что он запущен как MOUSE_POS, остался и изменился на MOUSE_BUTTONS (существуют другие комбинации). – Unreason

+0

@Noah: Я обновил запрос, чтобы он соответствовал последним изменениям. –

0

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 с, или вы могли бы написать процедуру, чтобы справиться с ними итеративно, такие как (псевдокод):

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 

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

0
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

Обновленный оператор SQL. – geffchang

+0

Извините, есть несколько других столбцов, которые я не привел в примере (в этом я их не забочусь), поэтому DISTINCT не отфильтровывал их. – Noah

0

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

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 

и отдыха то же самое.

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

Смежные вопросы