sql >> データベース >  >> RDS >> Sqlserver

SQLの文字列からchar、double、intパターンを読み取る

    最終版 (期待):

    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  

    1. ActiveRecord ::ConnectionTimeoutError:5.000秒以内にデータベース接続を取得できませんでした(5.000秒待機)

    2. 2つの条件が子レコードの異なる行で一致する場合にマスターレコードを取得するための高度なMysqlクエリ

    3. MySQLケース/If/ Then

    4. SQL、テーブル構造を更新する方法