2010-03-22 5 views
3

J'ai une table contenant des noms et leur carte d'identité associée, ainsi que d'un instantané:changements Détection entre les lignes avec la même ID

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

je dois identifier tous les name unique de que systemid a eu dans l'ensemble instantanés, mais seulement là où il y a eu au moins une fois le changement.

Par exemple, avec les données:

'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' 

... Je voudrais une requête qui renverra (dans l'ordre):

0, 'MOUSE_SPEED' 
0, 'MOUSE_BUTTONS' 

De plus, il serait utile de ont l'inverse - une liste de systemid s qui sont restés stables sur toussnapshot s (c'est-à-dire où le name n'a jamais changé). J'utilise PostgreSQL version 8.4.2.

EDIT:Mise à jour pour tenir compte des commentaires (désolé pour l'original moins-que-parfait après, je suis nouveau ici!).

+2

que feriez-vous vous la liste quand si elle change en instantané 3? – Unreason

+2

Si les valeurs d'instantané ne peuvent pas être commandées (directement ou via un autre champ), vous ne pouvez pas distinguer 2, 0, 'MOUSE_BUTTONS' et 3, 0, 'MOUSE_BUTTONS' des données d'exemple. Vous souciez-vous du choix? Si oui, comment l'avez-vous choisi pour l'exemple de résultat? – Unreason

+0

Je vous suggère de nous fournir des données réelles. Cela ne nous dérange pas d'aider, mais en laissant trop de choses à deviner ou en fournissant de mauvaises intrants, c'est juste une perte de temps et de votre temps. Considérant que vous êtes nouveau sur SO, je suis sûr que tout le monde comprend, mais prenez cela aussi bon conseil pour les questions futures. –

Répondre

0

La suite est avec SQL Server mais n'utilise pas de constructions spécifiques SQL Server. Il devrait être portable à postgresql.

Déclaration 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 

Les données de test

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

Désolé, le champ de capture instantanée est une chaîne, telle que 'PP16', 'PP16B', 'DS21'. Il n'y a pas de commande garantie - je ne vois pas les changements d'ordre qui ont été faits, seulement qu'ils ont été faits et les instantanés où ils ont été changés. – Noah

+1

@Noah, si vous ne pouvez pas établir l'ordre des instantanés à partir de sa valeur, vous ne pouvez pas établir dans lequel il a changé. Par exemple si PP16 est MOUSE_POS, PP16B est MOUSE_POS et DS21 est MOUSE_BUTTONS alors vous ne pouvez pas conclure dans lequel il a changé. Je peux affirmer qu'il est passé de MOUSE_POS à MOUSE_BUTTONS en MOUSE_POS, mais je peux également affirmer qu'il a démarré en tant que MOUSE_POS, qu'il est resté et modifié en MOUSE_BUTTONS (d'autres combinaisons existent). – Unreason

+0

@Noah: J'ai mis à jour la requête pour correspondre à vos dernières modifications. –

0

PostgreSQL a l'opérateur EXCEPT, qui, je le rappelle, est à peu près le même que MINUS (comme dans Oracle), alors peut-être que quelque chose comme ça fonctionnerait?

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') 

Si vous avez plusieurs shapshots, vous pouvez essayer de les concaténer tous dans une longue séquence de EXCEPT s, ou vous pouvez écrire une procédure pour les traiter de manière itérative, comme (pseudo-code):

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 

Cela semble vraiment être le genre de chose à utiliser pour les opérateurs.

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

Mise à jour de l'instruction SQL. – geffchang

+0

Désolé, il y a quelques autres colonnes que je n'ai pas listées dans l'exemple (je m'en fous dans ce contexte) donc DISTINCT ne les a pas filtrées. – Noah

0

Pour ceux qui ont changé:

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

vous donnerait l'instantané et l'identifiant de ceux qui ont changé

Pour ceux qui sont restés les mêmes

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

Rejoindre les valeurs à la première ou la dernière requête peut être fait avec sous-requête accolés ou corrélées sous_requête

Inscrit (exemple avec des noms qui a changé)

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 

corrélées (par exemple avec des noms qui est resté le même)

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) 

Si vous n'avez pas besoin de l'instantané pour la requête inverse alors

SELECT DISTINCT t2.systemid, t2.name 

et reposez la même.

Les requêtes ne sont pas validées, mais j'espère que les approches sont claires

Questions connexes