1

次のように作成された SQL Server 2008 テーブルがあるかどうか疑問に思っていました。

CREATE TABLE tbl (id INT PRIMARY KEY, 
                  dvt NVARCHAR(32), 
                  d0 TINYINT, 
                  d1 TINYINT, 
                  d2 TINYINT);
INSERT INTO tbl (id, dvt, d0, d1, d2) 
 VALUES(1, '1', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2) 
 VALUES(2, '', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2) 
 VALUES(3, '2,5', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2) 
 VALUES(4, '13, 34, 45, 5', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2) 
 VALUES(5, '1,8, 10', NULL, NULL, NULL);

「dvt」列から文字列を取得し、「d0」、「d1」、および「d2」列に分割する必要があります。「dvt」値はコンマで区切ることができます。

C# とトークン化関数を使用してこれを行うことができますが、SQL を使用して同じことを行うことができるかどうか疑問に思っていましたか?

前の列:

1, "1",             NULL, NULL, NULL
2, "",              NULL, NULL, NULL
3, "2,5",           NULL, NULL, NULL
4, "13, 34, 45, 5", NULL, NULL, NULL
5, "1,8, 10",       NULL, NULL, NULL

後の列:

1, "1",             1,    NULL, NULL
2, "",              NULL, NULL, NULL
3, "2,5",           2,    5,    NULL
4, "13, 34, 45, 5", 13,   34,   45  -- 5 is discarded
5, "1,8, 10",       1,    8,    10
4

4 に答える 4

1

このタイプのコードの主な問題は、計算の再利用です。

SQL Serverは結果のキャッシュに優れています(まったく同じ計算を5回入力CHARINDEX()すると、計算は1回だけで、その結果を4回再利用します)

しかし、そのコードを入力または維持しなければならない貧しいコーダーにとっては、それは少し慰めです。

SQL Server 2005以降CROSS APPLYでは、ある程度役に立ちます。ロジックは繰り返されますが、計算を繰り返し入力するのではなく、結果を繰り返し参照できます。

SELECT
  *,
  SUBSTRING(dvt, 1,            ISNULL(comma1.pos-1, LEN(dvt))           ) AS item1,
  SUBSTRING(dvt, comma1.pos+1, ISNULL(comma2.pos-1, LEN(dvt))-comma1.pos) AS item2,
  SUBSTRING(dvt, comma2.pos+1, ISNULL(comma3.pos-1, LEN(dvt))-comma2.pos) AS item3
FROM
(
  SELECT 'ab,c,def,hij' AS dvt
  UNION ALL
  SELECT 'xyz,abc'      AS dvt
)
  AS data
OUTER APPLY
  (SELECT NULLIF(CHARINDEX(',', data.dvt, 1           ), 0) AS pos                     )  AS comma1
OUTER APPLY
  (SELECT NULLIF(CHARINDEX(',', data.dvt, comma1.pos+1), 0) AS pos WHERE comma1.pos > 0)  AS comma2
OUTER APPLY
  (SELECT NULLIF(CHARINDEX(',', data.dvt, comma2.pos+1), 0) AS pos WHERE comma2.pos > 0)  AS comma3
OUTER APPLY
  (SELECT NULLIF(CHARINDEX(',', data.dvt, comma3.pos+1), 0) AS pos WHERE comma3.pos > 0)  AS comma4


もう1つのオプションは、これを実行するテーブル値のユーザー定義関数を作成することです(関数の結果が常に1行である場合でも)。次に、単にCROSS APPLYその機能を実行します。

于 2012-08-08T09:52:16.547 に答える
1

このようなことを試してください

 ;WITH Vals AS (
         SELECT id,
                dvt,
                CAST('<r>'+REPLACE(dvt,',','</r><r>')+'</r>' AS XML).query('/r[1]').value('.','varchar(max)') d1,
                CAST('<r>'+REPLACE(dvt,',','</r><r>')+'</r>' AS XML).query('/r[2]').value('.','varchar(max)') d2,
                CAST('<r>'+REPLACE(dvt,',','</r><r>')+'</r>' AS XML).query('/r[3]').value('.','varchar(max)') d3
         FROM   tbl
)
SELECT  id,
        dvt,
        CASE WHEN d1 = '' THEN NULL ELSE d1 END d1,
        CASE WHEN d2 = '' THEN NULL ELSE d2 END d2,
        CASE WHEN d3 = '' THEN NULL ELSE d3 END d3
FROM    Vals
于 2012-08-08T09:17:04.727 に答える
0

それが可能だ。

nullを繰り返し呼び出してCHARINDEXチェックすることでそれを行うことができますがFUNCTION、文字列を分割するために a を記述する方が適切で明確な場合があります。

于 2012-08-08T09:14:04.937 に答える
-2

Sybase 用の文字列トークナイザーが必要でした。名前データでは 1 つ以上のスペースで区切られている 名前の日付はクリーンで、コンマやその他の特殊文字は含まれていない

declare @test varchar(60)
select @test=str_replace(lower(rtrim('Jayanta  Narayan     Choudhuri'))," ",",")
exec sp_splitwords @test

これは、 http://www.sql9.com/?id= 102 の Kenny Lucas によるきちんとしたヒントに基づいています。

drop proc sp_splitwords
go
create proc sp_splitwords(@instr varchar(80)) as
begin
  declare @pos  int, 
          @word varchar(80), 
          @list varchar(81)

  create table #words(word varchar(80))    
  select @list = @instr + ','    
  set @pos = patindex('%,,%',@list)
  while @pos > 0
  begin
    select @list = str_replace(@list,',,',',')    
    set @pos = patindex('%,,%',@list)
  end


  set @pos = patindex('%,%',@list)

  while @pos > 0
  begin    
    set @word = substring(@list, 1,@pos-1)            
    set @list = substring(@list, @pos+1,len(@list)-@pos)    
    if NOT( @word is null OR LEN(@word) = 0 )
      insert into #words (word) values (@word)    
    set @pos = patindex('%,%',@list)
  end

  select * from #words
  order by len(word) desc

  drop table #words
end

Metaphone SQL 関数を Sybase http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=125724に移植できます。

Sybase は、美しい回避策 http://www.sypron.nl/quiz2008a.html#jan08からの関数の再帰を許可します

CREATE FUNCTION Metaphone2 (@str VARCHAR(100))
RETURNS VARCHAR(25) AS
BEGIN
  RETURN @str 
END

DROP FUNCTION Metaphone2
GO
CREATE FUNCTION Metaphone2 (@str VARCHAR(100))
RETURNS VARCHAR(25) AS
BEGIN
  RETURN dbo.Metaphone(@str)
END

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=125724から貼り付けられた関数の 1 行を変更

メタフォンと文字列トークナイザーの組み合わせは、名前の最初のミドルネームと姓、およびそれらのローテーションをファジー検索できることを意味します

于 2014-10-26T04:07:14.077 に答える