4

いろいろな薬の名前がついたプロジェクトに取り組んでいます。多くの場合、私はProscratinolやProscratinol XR(拡張リリース)のようなものを見つけるでしょう。この性質のすべての名前を取得するクエリを見つけて、「親」の薬をテーブルに入れ、これらの「子」の薬に参照させることができるようにしたいので、薬の数を数えるクエリを作成するときに、 XR、CR、およびその他のバージョンがあるため、Proscratinolを二重にカウントしていません。私はそれを突き刺すために次のように書いた

;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

これにより、名前が最初の5文字を​​共有するすべての薬のリストが表示されます。ここでは5つは完全に任意です。私がこれまでに得たものは十分にうまくいきますが、私は結果を降順で並べたいと思います。ですから、左から読んでいるXのほとんどの文字が同じであることを確認したいと思います。

たとえば、フェニトインとフェピルは3になります(最初の3文字は同じです)

; xを使用(drug_nameでrxグループからdrug_nameを選択)

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をleft関数にハードコーディングする代わりに、2つの文字列が共有する類似文字の数を返す整数式が必要です。これを行うための良い方法はありますか?

4

2 に答える 2

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条項は、次の3つの条件をチェックしています。(1)各薬剤名の左側がseqnumまで同じであること。(2)各薬剤名の長さがseqnum以下であること。

次に、集計は各ペアを取得し、seqnumの最大値を選択します。これは、最も長い部分文字列の一致である必要があります。

于 2013-03-20T15:40:09.347 に答える
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
于 2013-07-01T19:50:29.160 に答える