web-dev-qa-db-ja.com

列のないROW_NUMBER()をORDER BYに追加しますか?

したがって、私は コードゴルフパズル に取り組んでおり、INT "数値"列nを結果に追加する必要があります。現在の順序を維持します。

私のソースデータが次のとおりだとしましょう:

_SELECT value
FROM STRING_SPLIT('one,two,three,four,five', ',')
_

これにより、アイテムが元の(望ましい)順序で返されます。

_value
-----
one
two
three
four
five
_

ROW_NUMBER()またはRANK()を使用しようとすると、_ORDER BY_を指定せざるを得なくなります。valueが唯一の正当な選択肢です。

_SELECT value, n = ROW_NUMBER() OVER(ORDER BY value)
FROM STRING_SPLIT('one,two,three,four,five',',')
_

しかし、これは(予想どおり)目的の元の順序のままにする代わりに、valueをアルファベット順に並べ替えます。

_value   n
------ ---
five    1
four    2
one     3
three   4
two     5
_

WHERE句がないと完全な外部結合を取得するため、数値テーブルへの結合は機能しません。

私が思いつくことができる最高のものについては、識別フィールドを持つ一時テーブルを使用することでした:

_CREATE TABLE #argg (n INT IDENTITY(1,1), v VARCHAR(99))

INSERT #argg 
SELECT value v
FROM STRING_SPLIT('one,two,three,four,five',',')

SELECT *
FROM #argg

DROP TABLE #argg
_

しかし、これは本当に長くて面倒です。より良いアイデアはありますか?

7
BradC

これを行う正規の方法は次のとおりです:ROW_NUMBER() OVER(ORDER BY (SELECT NULL))。あなたがゴルフをしているなら、あなたはこのようなことを試みるかもしれません:

_SELECT value, n = ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM STRING_SPLIT('one,two,three,four,five',',')
_

これは、質問に投稿した単純なケースで機能します。

enter image description here

ROW_NUMBER()の値が期待どおりの正確な順序になるという文書化された保証はありません。しかし、それはコードゴルフなので、これで十分に思えます。

10
Joe Obbish

INSERTを使用して、元の文字列の順序でIDENTITY値を生成することはできません。それはあなたが観察することかもしれませんが、それは単なる幸運な偶然であり、確かに保証されていません。

重複がない場合は、以下が機能します。

DECLARE @str varchar(255) = 'one,two,three,four,five';

SELECT value, n = ROW_NUMBER() OVER
  (ORDER BY CHARINDEX(',' + value + ',', ',' + @str + ','))
FROM STRING_SPLIT('one,two,three,four,five', ',')
ORDER BY n;

コードゴルフの場合:

DECLARE @s char(99)='one,two,three,four,five';
SELECT value,n=RANK() OVER(ORDER BY CHARINDEX(','+value+',',','+@s+','))
FROM STRING_SPLIT('one,two,three,four,five', ',')ORDER BY n

重複がある場合は、さらに複雑になります。ここにいくつかのアイデアがあります:

6
Aaron Bertrand

別のオプションはシーケンスを使用することです:

DROP SEQUENCE IF EXISTS dbo.S;
CREATE SEQUENCE dbo.S START WITH 1;

SELECT value, NEXT VALUE FOR dbo.S 
FROM STRING_SPLIT('one,two,three,four,five', ',');

出力:

╔═══════╦═══╗
║ one   ║ 1 ║
║ two   ║ 2 ║
║ three ║ 3 ║
║ four  ║ 4 ║
║ five  ║ 5 ║
╚═══════╩═══╝

STRING_SPLITは、組み込みの番号付けオプションなしで実装されました。変更に投票 https://feedback.Azure.com/forums/908035-sql-server/suggestions/32902852-string-split-is-not-feature-complete

5
Paul White 9

あなたの質問からもう一つの選択肢を追加するだけです。しかし、順序は保証されていないと思います、

SELECT value v,IDENTITY(INT,1,1) AS n
INTO #argg
FROM STRING_SPLIT('one,two,three,four,five',',')

SELECT * FROM #argg
2
Biju jose