我正在开展一个名为各种药物的项目。通常,我会找到类似Proscratinol和Proscratinol XR(延长版)的东西。我想找一个查询,以了解这种性质的所有名称,所以我可以将'父母'药物放在一张桌子中并让这些'儿童'药物参考它,所以当我写一个查询做药物计数时,我我不会重复计算Proscratinol,因为它有XR,CR和其他任何版本。我写了以下内容以便对它进行一次尝试
;with x
as
(
select drug_name
from rx
group by drug_name
)
select distinct *
from x,x as x2
where LEFT(x2.drug_name,5) = LEFT(x.drug_name,5)
and x.drug_name !=x2.drug_name
这将为我提供所有药物的清单,这些药物的名称与前五个字母相同。五是完全随意的。到目前为止我所做的已经足够好了,但我想通过降序来命令结果。所以我想找到他们从左边读的X字符是相同的。
e.g。 Phenytoin和Phepil将是3(他们的前三个字母是相同的)
;用x 如 ( 选择drug_name 来自rx 按药物名称分组 )
select x.drug_name as xDrugName
,x2.drug_name as x2DrugName
,case when LEFT(x2.drug_name,6) = LEFT(x.drug_name,6)
then LEN(left(x.drug_name,6)) else '0' end
from x,x as x2
where LEFT(x2.drug_name,5) = LEFT(x.drug_name,5)
and x.drug_name !=x2.drug_name
group by x.drug_name,x2.drug_name
我不需要在上面的查询中将int硬编码到左侧函数中,而是需要该整数表达式来返回两个字符串共享的相似字符数。有什么好办法吗?
答案 0 :(得分:2)
这种方法使用数字生成器,然后只测试重叠的长度:
select x.drug_name, x2.drug_name, MAX(c.seqnum) as OverlapLen
from x cross join
x x2 cross join
(select ROW_NUMBER() over (order by (select NULL)) seqnum
from INFORMATION_SCHEMA.COLUMNS c
) c
where LEFT(x.drug_name, c.seqnum) = LEFT(x2.drug_name, c.seqnum) and
len(x.drug_name) >= c.seqnum and len(x2.drug_name) >= c.seqnum
group by x.drug_name, x.drug_name
order by x.drug_name, OverlapLen desc
这假定information_schema.columns
有足够的行用于较长的药物名称。
这会将x
连接到自身,然后加入一个数字列表。 where
条款检查三个条件:(1)每个药品名称的左侧部分与seqnum相同; (2)每种药物名称的长度小于或等于seqnum。
聚合然后获取每一对并选择seqnum的最高值 - 这应该是最长的子串匹配。
答案 1 :(得分:0)
你想要最长的共同序列。这是一个SQL服务器实现:
选择dbo.lcs(@ string1,@ string2),len(@ string1),len(@ string2)
CREATE FUNCTION [dbo].[LCS]( @s varchar(MAX), @t varchar(MAX) )
RETURNS INT AS
BEGIN
DECLARE @d varchar(MAX), @LD INT, @m INT, @n INT, @i INT, @j INT,
@s_i NCHAR(1), @t_j NCHAR(1)
SET @n = LEN(@s)
IF @n = 0 RETURN 0
SET @m = LEN(@t)
IF @m = 0 RETURN 0
SET @d = REPLICATE(CHAR(0),(@n+1)*(@m+1))
SET @i = 1
WHILE @i <= @n BEGIN
SET @s_i = SUBSTRING(@s,@i,1)
SET @j = 1
WHILE @j <= @m BEGIN
SET @t_j = SUBSTRING(@t,@j,1)
IF @s_i = @t_j
SET @d = STUFF(@d,@j*(@n+1)+@i+1,1,
NCHAR(UNICODE(
SUBSTRING(@d, (@j-1)*(@n+1)+@i-1+1, 1)
)+1))
ELSE
SET @d = STUFF(@d,@j*(@n+1)+@i+1,1,CHAR(dbo.Max2(
UNICODE(SUBSTRING(@d,@j*(@n+1)+@i-1+1,1)),
UNICODE(SUBSTRING(@d,(@j-1)*(@n+1)+@i+1,1)))))
SET @j = @j+1
END
SET @i = @i+1
END
SET @LD = UNICODE(SUBSTRING(@d,@n*(@m+1)+@m+1,1))
RETURN @LD
END