1

簡単にするために、当面の間、結果を一時テーブルに保存した複雑なクエリがあります。以下のスクリーンキャップなど、3文字の一意の識別子の特定の組み合わせのコンマ=区切りリストがあります。

ここに画像の説明を入力してください

2行目と3行目で、3文字の識別子は同じですが順序が逆になっていることがわかります。カウントは異なりますが、それらの値は正しいです(XとYの人口サイズが等しくない場合、XとYの人の数はYとXの人の数とは異なります)。出現する順番に関係なく、すべての薬のユニークな組み合わせを見つけたいと思います。row_number()行2と3に1と2を与えるパーティションを持つaの ようなものを想像します。

私はSQLでこのようなことを試みたことがありませんが、私の考えは

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 

リストはコンマで区切られているため、case whenステートメントは行内のコンマの数を検索し、検索する3桁のスパンの数を示します。2つの薬剤(1つのコンマ)を含むalldrugs列の場合、結果をCTEにし、そのCTEに自己結合して、かどうかを確認できright(alldrugs,3) = left(alldrugs,3)ます。これは明らかに拡張可能ではありません。このようなユニークな組み合わせを得る慣用的な方法はありますか?

4

2 に答える 2

2

Ok。これは、考えられるすべての3文字コードのリストがどこかにあることを前提とした1つのアイデアです。リストを展開して、行ごとに1行になるようにしてから、結果を再結合するという考え方です。group_concat別のデータベースでは、またはを使用できますlistagg。SQL Serverの場合、集合関数を使用する必要があります。

リストを展開するには:

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+',%'
   )

次に、自己結合は、セットが同じであるかどうかを識別する1つの方法です。2つのセット(「id」)が同じ数の薬剤を持ち、すべてが一致する場合、それらは同じです。したがって、元のテーブルの各行について、同じ薬を含む最小の行を見つけます。これは、グループ化の目的でIDになります。

次の(テストされていない)クエリはこれを実装します:

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
于 2012-11-21T18:59:13.703 に答える
1

SQL Server 2008以降を使用している場合は、カスタムsplit関数と関数の組み合わせを使用しSTUFFて、リストを並べ替えられた順序に分割および再結合できます。次に、再配置されたリストから個別に選択して、一意の組み合わせのみを取得できます。

splitこれが機能するはずの単純な関数です(ソース):

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

次に、個別のリストを取得するためのクエリを示します。

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

デモ:http ://www.sqlfiddle.com/#!3 / d890b / 4

サンプル出力:

| ALLDRUGSORDERED |
-------------------
|         H2F,H3A |
|             H2S |
|             H3A |
|         H3A,H4B |
|         H3A,H6H |
|             H4B |
|             H6H |
|             J7C |
于 2012-11-21T19:32:44.507 に答える