1

我有一个复杂的查询,为了简单起见,我暂时将其结果存储在一个临时表中。我有一个逗号=分隔的三个字符唯一标识符组合的列表,例如下面的屏幕截图:

在此处输入图像描述

您可以在第 2 行和第 3 行中看到 3 个字符标识符相同,但顺序相反。计数不同,但这些值是正确的(如果 X 和 Y 的人口规模不相等,则具有 X 和 Y 的人数与具有 Y 和 X 的人数不同)。我想找到所有药物的独特组合,无论它们出现的顺序如何。我设想类似于 arow_number()的分区,它为第 2 行和第 3 行提供 1 和 2。

我从来没有在 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 种药物(一个逗号)的 alldrugs 列,我可以将结果设为 CTE,在该 CTE 上自行加入并检查是否right(alldrugs,3) = left(alldrugs,3). 这显然是不可扩展的。有没有一种惯用的方法来获得这样的独特组合?

4

2 回答 2

2

好的。这是一个想法,假设您在某处拥有所有可能的 3 个字母代码的列表。这个想法是扩展列表,所以每一行都有一行,然后重新组合结果。在另一个数据库中,您可以使用group_concator listagg。对于 SQL Server,我们将不得不使用 set 函数。

展开列表:

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

接下来,自联接是识别集合何时相同的一种方法。如果两组(“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这是一个应该可以工作的简单函数( 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

然后这是一个获取不同列表的查询:

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 回答