2009-06-05 11 views
2

J'ai une table de base de données structurée comme celui-ci (champs non pertinents omis par souci de concision):SQL: Trouver les lignes où la valeur du champ diffère

rankings 
------------------ 
(PK) indicator_id 
(PK) alternative_id 
(PK) analysis_id 
rank 

Tous les champs sont des nombres entiers; les trois premiers (étiquetés "(PK)") sont une clé primaire composite. Une «analyse» donnée a plusieurs «alternatives», chacune ayant un «rang» pour chacun des nombreux «indicateurs».

Je cherche un moyen efficace de comparer un nombre arbitraire d'analyses dont les rangs pour toute combinaison alternative/indicateur diffèrent. Ainsi, par exemple, si nous avons ces données:

analysis_id | alternative_id | indicator_id | rank 
---------------------------------------------------- 
      1 |    1 |   1 | 4 
      1 |    1 |   2 | 6 
      1 |    2 |   1 | 3 
      1 |    2 |   2 | 9 
      2 |    1 |   1 | 4 
      2 |    1 |   2 | 7 
      2 |    2 |   1 | 4 
      2 |    2 |   2 | 9 

... alors la méthode idéale d'identifier les différences suivantes:

analysis_id | alternative_id | indicator_id | rank 
---------------------------------------------------- 
      1 |    1 |   2 | 6 
      2 |    1 |   2 | 7 
      1 |    2 |   1 | 3 
      2 |    2 |   1 | 4 

Je suis arrivé avec une requête qui fait ce que je veux pour 2 ID d'analyse, mais j'ai du mal à le généraliser pour trouver des différences entre un nombre arbitraire d'ID d'analyse (ie l'utilisateur pourrait vouloir comparer 2, ou 5, ou 9, ou autre, et trouver des lignes où au moins une analyse diffère de l'un des autres). Ma requête est:

declare @analysisId1 int, @analysisId2 int; 
select @analysisId1 = 1, @analysisId2 = 2; 

select 
    r1.indicator_id, 
    r1.alternative_id, 
    r1.[rank] as Analysis1Rank, 
    r2.[rank] as Analysis2Rank 
from rankings r1 
inner join rankings r2 
    on r1.indicator_id = r2.indicator_id 
     and r1.alternative_id = r2.alternative_id 
     and r2.analysis_id = @analysisId2 
where 
    r1.analysis_id = @analysisId1 
    and r1.[rank] != r2.[rank] 

(. Il met les valeurs d'analyse dans des champs supplémentaires au lieu de lignes, je pense que de toute façon fonctionnerait.)

Comment puis-je généraliser cette requête pour traiter de nombreux ids d'analyse? (Ou, alternativement, venir avec une requête différente et meilleure pour faire le travail?) J'utilise SQL Server 2005, au cas où cela serait important.

Si nécessaire, je peux toujours extraire toutes les données du tableau et rechercher des différences de code, mais une solution SQL serait préférable car souvent je ne m'intéresse qu'à quelques lignes sur des milliers et cela ne sert à rien en les transférant tous si je peux l'éviter. (Cependant, si vous avez une raison impérieuse de ne pas le faire en SQL, dites-le - je pense que c'est une bonne réponse!)

Répondre

2

Cela renverra votre ensemble de données désiré - Maintenant, vous avez juste besoin d'un moyen de transmettre l'analyse requise ids à la requête. Ou potentiellement juste filtrer ces données dans votre application.

select r.* from rankings r 
    inner join 
    (
     select alternative_id, indicator_id 
     from rankings 
     group by alternative_id, indicator_id 
     having count(distinct rank) > 1 
    ) differ on r.alternative_id = differ.alternative_id 
    and r.indicator_id = differ.indicator_id 
    order by r.alternative_id, r.indicator_id, r.analysis_id, r.rank 
+0

Parfait - et des points de bonus pour le faire sans une table temporaire! Merci! –

1

Je ne sais pas quelle base de données vous utilisez, dans SQL Server I irait comme ceci:

-- STEP 1, create temporary table with all the alternative_id , indicator_id combinations with more than one rank: 
select alternative_id , indicator_id 
into #results 
from rankings 
group by alternative_id , indicator_id 
having count (distinct rank)>1 

-- STEP 2, retreive the data 

select a.* from rankings a, #results b 
where a.alternative_id = b.alternative_id 
and a.indicator_id = b. indicator_id 
order by alternative_id , indicator_id, analysis_id 

BTW, les autres réponses données ici ont besoin du nombre (rang distinct) !!!!!

+0

C'est exactement ce que je demandais - merci! Je dois donner le signe de tête à Dan pour l'avoir retiré sans une table temporaire. ;-) –

+0

ahhh, j'adore les tables temporaires !!! désolé à ce sujet :-) – tekBlues

0

Je pense que c'est ce que vous essayez de faire:

select 
    r.analysis_id, 
    r.alternative_id, 
    rm.indicator_id_max, 
    rm.rank_max 
from rankings rm 
    join (
     select 
      analysis_id, 
      alternative_id, 
      max(indicator_id) as indicator_id_max, 
      max(rank) as rank_max 
     from rankings 
     group by analysis_id, 
      alternative_id 
     having count(*) > 1 
    ) as rm 
    on r.analysis_id = rm.analysis_id 
    and r.alternative_id = rm.alternative_id 
0

Vous différences d'exemple semble faux. Vous dites que vous voulez analyses dont les rangs pour toute combinaison alternative/indicateur différent mais les exemples de lignes 3 et 4 ne satisfont pas ce critère. Un résultat correct en fonction de votre exigence est la suivante:

analysis_id | alternative_id | indicator_id | rank 
---------------------------------------------------- 
     1 |    1 |   2 | 6 
     2 |    1 |   2 | 7 
     1 |    2 |   1 | 3 
     2 |    2 |   1 | 4 

Sur requête, vous pouvez essayer est ceci:

with distinct_ranks as (
    select alternative_id 
    , indicator_id 
    , rank 
    , count (*) as count 
    from rankings 
     group by alternative_id 
     , indicator_id 
     , rank 
    having count(*) = 1) 
select r.analysis_id 
    , r.alternative_id 
    , r.indicator_id 
    , r.rank 
from rankings r 
    join distinct_ranks d on r.alternative_id = d.alternative_id 
     and r.indicator_id = d.indicator_id 
     and r.rank = d.rank 

Vous devez comprendre que l'analyse multiple des critères que vous avez est ambigu.Que se passe-t-il si les analyses 1, 2 et 3 ont le rang 1 et 4, 5 et 6 ont le rang 2 pour la variante/l'indicateur 1/1? L'ensemble (1,2,3) est 'différent' de l'ensemble (4,5,6) mais à l'intérieur de chaque ensemble il n'y a pas de différence. quel est le comportement que vous désirez dans ce cas, devraient-ils apparaître ou non? Ma requête trouve tous les enregistrements qui ont un rang différent pour la même alternative/indicateur * de toutes les autres analyses 'mais n'est pas clair si cela est correct dans vos besoins.

+0

Vous avez raison, l'exemple était imparfait - ma faute de frappe, maintenant corrigé. Merci de l'avoir attrapé. Le comportement souhaité est de transmettre toute combinaison d'identifiants d'analyse à cette requête et de lui renvoyer les lignes où les rangs diffèrent. Donc dans votre exemple, si je passais dans l'ensemble (1,2,3), aucune ligne ne serait retournée. De même si je suis passé (4,5,6). Mais si je réussissais (1,4), cela reviendrait aux rangs différents. Les réponses de Dan et de tekBlues reflètent mon comportement souhaité, après quelques légères modifications pour tenir compte des ID d'analyse particuliers. –

+0

Qu'en est-il de (1,2,4,5), devraient tous être retournés? –

+0

Oui, c'est vrai. –

Questions connexes