2012-11-21 3 views
1

J'ai une requête compliquée dont les résultats ont été stockés dans une table temporaire pour l'instant par souci de simplicité. J'ai une liste délimitée par des virgules = de certaines combinaisons de trois caractères identificateurs uniques tels que le capuchon d'écran ci-dessous:Trouver une combinaison unique d'identifiants dans une liste délimitée par des virgules

enter image description here

Vous pouvez voir dans les lignes 2 et 3 que les 3 identificateurs de caractères sont les mêmes, mais dans l'ordre inverse. Les chiffres sont différents, mais ces valeurs sont correctes (le nombre de personnes avec X et Y est différent du nombre de personnes avec Y et X si les tailles de population de X et Y ne sont pas égales). Je voudrais trouver les combinaisons uniques de tous les médicaments, indépendamment de l'ordre dans lequel ils apparaissent. J'imagine quelque chose comme un row_number() avec une partition qui nous donne 1 et 2 pour les lignes 2 et 3.

Je ne l'ai jamais essayé quelque chose comme ça dans SQL, mais ma pensée était quelque chose le long des lignes de

select *, 
    case when LEN(alldrugs)-LEN(replace(alldrugs,',',''))= 1 then 2 
     when LEN(alldrugs)-LEN(REPLACE(alldrugs,',',''))= 2 then 3 
     when LEN(alldrugs)-LEN(REPLACE(alldrugs,',',''))= 3 then 4 
     when LEN(alldrugs)-LEN(REPLACE(alldrugs,',',''))= 4 then 5 
     when LEN(alldrugs)-LEN(REPLACE(alldrugs,',',''))= 5 then 6 
     else 1 end as numDrugs 
    from #testfix as tf 
    order by alldrugs,numDrugs 

Étant donné que la liste est délimitée par des virgules, l'instruction case when trouve le nombre de virgules dans une ligne et indique le nombre de segments à trois chiffres à rechercher. Pour les colonnes alldrugs avec 2 médicaments (une virgule), je pourrais faire les résultats d'un CTE, auto-rejoindre sur ce CTE et vérifier si right(alldrugs,3) = left(alldrugs,3). Ceci n'est évidemment pas extensible. Existe-t-il un moyen idiomatique d'obtenir des combinaisons uniques comme celle-ci?

+1

Exemple de violon: http://www.sqlfiddle.com/#!3/18468/1 – mellamokb

+0

@mellamokb merci pour cela.J'en inclurai un à partir de maintenant. – wootscootinboogie

+0

Combien de codes de médicaments distincts avez-vous? – MatBailie

Répondre

1

En supposant que vous utilisez SQL Server 2008+, vous pouvez utiliser une combinaison d'une fonction personnalisée split et la fonction STUFF de diviser et recombiner les listes en ordre trié. Vous pouvez ensuite sélectionner distinct parmi les listes réorganisées pour obtenir uniquement des combinaisons uniques.

est ici une simple fonction split qui devrait fonctionner (source):

CREATE FUNCTION dbo.Split 
(
    @RowData nvarchar(2000), 
    @SplitOn nvarchar(5) 
) 
RETURNS @RtnValue table 
(
    Id int identity(1,1), 
    Data nvarchar(100) 
) 
AS 
BEGIN 
    Declare @Cnt int 
    Set @Cnt = 1 

    While (Charindex(@SplitOn,@RowData)>0) 
    Begin 
     Insert Into @RtnValue (data) 
     Select 
      Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1))) 

     Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData)) 
     Set @Cnt = @Cnt + 1 
    End 

    Insert Into @RtnValue (data) 
    Select Data = ltrim(rtrim(@RowData)) 

    Return 
END 

Alors voici une requête pour saisir les listes distinctes:

select 
    distinct 
    STUFF((select ',' + data as [text()] 
     from dbo.split(tf.alldrugs, ',') 
     order by data 
     FOR XML PATH('')) , 1 , 1 , '') as alldrugsordered 

from 
    TestFix tf 

Démo: http://www.sqlfiddle.com/#!3/d890b/4

Exemple de sortie :

| ALLDRUGSORDERED | 
------------------- 
|   H2F,H3A | 
|    H2S | 
|    H3A | 
|   H3A,H4B | 
|   H3A,H6H | 
|    H4B | 
|    H6H | 
|    J7C | 
+0

cela a bien fonctionné. J'ai rejoint cette table aux résultats que j'ai déjà et alto! – wootscootinboogie

2

Ok. Voici une idée, qui suppose que vous avez une liste de tous les codes de 3 lettres possibles quelque part. L'idée est d'étendre la liste, donc il y a une ligne pour chaque ligne, puis de recombiner les résultats. Dans une autre base de données, vous pouvez utiliser ou listagg. Pour SQL Server, nous devrons utiliser des fonctions set.

Pour développer la liste:

with fulllist as (
    select yt.*, c.code, row_number() over (order by (select NULL)) as id 
    from YourTable yt join 
     Codes c 
     on ','+yt.AllDrugs+',' like '%,'+c.code+',%' 
    ) 

Ensuite, une jointure réflexive est une façon d'identifier quand les jeux sont les mêmes. Si deux séries ("id") ont le même nombre de médicaments et correspondent tous, alors ils sont les mêmes. Ainsi, pour chaque ligne du tableau d'origine, nous trouverons la rangée minimale qui a les mêmes médicaments. Cela devient l'identifiant pour le regroupement.

La requête suivante (non testé) met en œuvre ceci:

with fulllist as (
    select yt.*, c.code 
    from YourTable yt join 
     Codes c 
     on ','+yt.AllDrugs+',' like '%,'+c.code+',%' 
    ), 
    Pairs as (
    select id1, min(id2) as minId 
    from (select fl1.id as id1, fl2.id as id2 
      from (select fl.*, count(*) over (partition by yt.id) as NumCodes 
       from fulllist fl 
       ) fl1 join 
       (select fl.* count(*) over (partition by yt.id 
       from fulllist fl 
       ) fl2 
       on fl1.code = fl2.code and 
        fl1.NumCodes = fl2.NumCodes 
      group by fl1.id, fl2.id 
      having count(*) as fl1.NumCodes 
     ) t 
    group by id1 
    ) 
select p.minId, min(fl.AllDrugs), sum(fl.DrugFamilyCounts) 
from FullList fl join 
    Pairs p 
    on fl.id = p.minId 
group by p.minId 
order by 2 desc 
+0

Je pensais dans ce sens, mais mes idées n'étaient pas aussi étoffées. Je vais devoir faire une liste de tous les combos possibles et y arriver. – wootscootinboogie

+1

D'un commentaire l'OP est parti, il y a seulement 7 codes de drogue disinct. C'est seulement 128 combinaisons * (y compris sans médicaments, tout le long de chaque médicament) *. La * 'combinaison id' * peut être établie en donnant à chaque code de drogue une valeur différente de cette liste; «1,2,4,8,16,32,64». La somme de ces valeurs donnera un résultat distinct de 0 à 127 pour chaque combinaison * (indépendamment de l'ordre de la permutation) *. * (En supposant que chaque combinaison de codes de médicaments ne peut avoir que 0 ou 1 de chaque code de drogue.) * – MatBailie

+0

@wootscootinboogie - Je pense que vous avez mal compris la réponse; la table 'codes' proposée ne nécessite que chacun des 7 médicaments, pas une liste des 128 combinaisons. – MatBailie

Questions connexes