我有一个复杂的查询,其结果我暂时存储在一个临时表中,以简化起见。我有一个逗号=分隔的三个字符唯一标识符组合的列表,如下面的屏幕截图:
您可以在第2行和第3行中看到3个字符标识符相同,但顺序相反。计数是不同的,但这些值是正确的(如果X和Y的人口规模不相等,则具有X和Y的人数与具有Y和X的人数不同)。我想找到alldrugs的独特组合,无论它们出现的顺序如何。我想象一个像row_number()
这样的分区,它给我们1和2代表第2行和第3行。
我从未在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)
。这显然不可扩展。是否有一种惯用的方式来获得这样的独特组合?
答案 0 :(得分:2)
确定。这是一个想法,假设您有一个所有可能的3个字母代码的列表。我们的想法是扩展列表,因此每行有一行,然后重新组合结果。在另一个数据库中,您可以使用group_concat
或listagg
。对于SQL Server,我们必须使用set functions。
要展开列表:
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
答案 1 :(得分: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 |