最終版 (期待):
SQL Server 2008 は集計関数の over 句で order by をサポートしていないため、sum
の代わりに行インデックスを追加する別の cte を追加しました。 以前のバージョンで使用したもの:
;WITH cteAllRows as( SELECT Item, ItemIndex, CASE WHEN ISNUMERIC(Item) =0 THEN 'String' WHEN ISNUMERIC(Item) =1 AND CHARINDEX('.', Item)> 0 THEN 'Double' WHEN ISNUMERIC(Item) =1 AND CHARINDEX('.', Item) =0 THEN 'Integer' END As DataType FROM dbo.SplitStrings_Numbers(@string, ',')), cteAll as( SELECT Item, DataType, ItemIndex, ( SELECT COUNT(*) FROM cteAllRows tInner WHERE tInner.DataType ='String' AND tInner.ItemIndex <=tOuter.ItemIndex ) As RowIndex FROM cteAllRows tOuter)
プレ>あとは前のバージョンと同じです。
更新
最初に行ったのは、文字列分割関数を集計テーブルに基づく関数に変更して、行番号を簡単に追加できるようにすることです。したがって、まだ集計表がない場合は、 作成 集計表とは何か、なぜそれが必要なのかを自問している場合は、Jeff Moden によるこの記事を読む :
SELECT TOP 10000 IDENTITY(int,1,1) AS Number INTO Tally FROM sys.objects s1 CROSS JOIN sys.objects s2 ALTER TABLE Tally ADD CONSTRAINT PK_NumbersTest PRIMARY KEY CLUSTERED (Number)GO
プレ>次に、集計テーブルに基づいて文字列分割関数を作成します (Aaron の記事から引用しましたが、行インデックス列を追加しました):
CREATE FUNCTION dbo.SplitStrings_Numbers( @List NVARCHAR(MAX), @Delimiter NVARCHAR(255))RETURNS TABLEWITH SCHEMABINDINGAS RETURN ( SELECT Item =SUBSTRING(@List, Number, CHARINDEX(@Delimiter, @List + @) Delimiter, Number) - Number), ROW_NUMBER() OVER (ORDER BY Number) As ItemIndex FROM dbo.Tally WHERE Number <=CONVERT(INT, LEN(@List)) AND SUBSTRING(@Delimiter + @List, Number, LEN( @Delimiter)) =@Delimiter );GO
プレ>さて、私が使用したトリックは前のものと非常によく似ています.RowIndexと呼ばれる新しい列を最初のcteに追加しただけです.すべての行のインデックス:
SELECT Item, CASE WHEN ISNUMERIC(Item) =0 THEN 'String' WHEN ISNUMERIC(Item) =1 AND CHARINDEX('.', Item)> 0 THEN 'Double' WHEN ISNUMERIC(Item) =1 AND CHARINDEX('.', Item) =0 THEN 'Integer' END As DataType, SUM(CASE WHEN ISNUMERIC(Item) =0 THEN 1 END) OVER(ORDER BY ItemIndex) As RowIndex FROM dbo.SplitStrings_Numbers(@string, ' ,')
プレ>この結果が得られました:
Item DataType RowIndex---------- -------- -----------ddd String 11.5 Double 11 Integer 1eee String 22.3 Double 20 Integer 2fff 文字列 31.2 ダブル 3ggg 文字列 46.123 ダブル 41 整数 4
プレ>ご覧のとおり、各行に番号があるので、これからは簡単です:
;WITH cteAll as( SELECT Item, CASE WHEN ISNUMERIC(Item) =0 THEN 'String' WHEN ISNUMERIC(Item) =1 AND CHARINDEX('.', Item)> 0 THEN 'Double' WHEN ISNUMERIC (Item) =1 AND CHARINDEX('.', Item) =0 THEN 'Integer' END As DataType, SUM(CASE WHEN ISNUMERIC(Item) =0 THEN 1 END) OVER(ORDER BY ItemIndex) As RowIndex FROM dbo.SplitStrings_Numbers (@string, ',')), cteString AS( SELECT Item, RowIndex FROM cteAll WHERE DataType ='String'), cteDouble AS( SELECT Item, RowIndex FROM cteAll WHERE DataType ='Double'), cteInteger AS( SELECT Item, RowIndex FROM cteAll WHERE DataType ='Integer')SELECT T1.Item As [String], T2.Item As [Double], T3.Item As [Integer] FROM dbo.Tally LEFT JOIN cteString T1 ON T1.RowIndex =Number LEFT JOIN cteDouble T2 ON t2.RowIndex =Number LEFT JOIN cteInteger T3 ON t3.RowIndex =NumberWHERE COALESCE(T1.Item, T2.Item, T3.Item) IS NOT NULL
プレ>この結果が得られました:
String Double Integer---------- ---------- ----------ddd 1.5 1eee 2.3 0fff 1.2 NULLggg 6.123 1コード> プレ>
ご覧のとおり、アイテムは文字列内の元の順序で並べ替えられています。挑戦していただきありがとうございます。
最初の試み
まず、その文字列をテーブルに分割する必要があります。これを行うには、ユーザー定義関数を使用する必要があります。 Aaron Bertrand の Split strings the正しい方法 – または次善の方法
このデモでは、
SplitStrings_XML
を使用することにしました。 .まず、関数を作成します:
CREATE FUNCTION dbo.SplitStrings_XML( @List NVARCHAR(MAX), @Delimiter NVARCHAR(255))RETURNS TABLEWITH SCHEMABINDINGAS RETURN ( SELECT Item =y.i.value('(./text())[1]', 'nvarchar(4000)') FROM ( SELECT x =CONVERT(XML, '' + REPLACE(@List, @Delimiter, '') + '')).クエリ('.') ) AS a CROSS APPLY x.nodes('i') AS y(i) );GO
プレ>次に、変数を宣言して初期化します:
declare @string nvarchar(max) ='ddd,1.5,1,eee,2.3,0,fff,1.2,ggg,6.123,1'
プレ>次に、4 つの 共通テーブル式 を作成します。 - すべての項目に 1 つ、文字列に 1 つ、double に 1 つ、整数に 1 つ。
row_number()
の使用に注意してください。 関数 - 後ですべての結果を結合するために使用されます:;WITH AllItems as( SELECT Item, ROW_NUMBER() OVER(ORDER BY (select null)) as rn FROM dbo.SplitStrings_XML(@string, ',')), Strings as( SELECT Item as StringItem, ROW_NUMBER() OVER(ORDER BY (select null)) as rn FROM dbo.SplitStrings_XML(@string, ',') WHERE ISNUMERIC(Item) =0), Doubles as ( SELECT Item as DoubleItem, ROW_NUMBER() OVER(ORDER BY (select null)) as rn FROM dbo.SplitStrings_XML(@string, ',') WHERE ISNUMERIC(Item) =1 AND CHARINDEX('.', Item)> 0), Integers as( SELECT Item as IntegerItem, ROW_NUMBER() OVER(ORDER BY (select null)) as rn FROM dbo.SplitStrings_XML(@string, ',') WHERE ISNUMERIC(Item) =1 AND CHARINDEX('.', Item) =0 )
プレ>次に、これらすべての共通テーブル式の結合から選択します。
COALESCE
の使用に注意してください。 少なくとも 1 つの値が存在する行のみを返す組み込み関数:SELECT StringItem, DoubleItem, IntegerItemFROM AllItems ALEFT JOIN Strings S ON A.rn =S.rnLEFT JOIN Doubles D ON A.rn =D.rnLEFT JOIN Integers I ON A.rn =I.rnWHERE COALESCE(StringItem 、DoubleItem、IntegerItem) は NULL ではありません
プレ>結果:
StringItem DoubleItem IntegerItem---------- ---------- -----------ddd 1.5 1eee 2.3 0fff 1.2 1ggg 6.123 NULLコード> プレ>