it-swarm.com.de

Hinzufügen einer ROW_NUMBER () ohne Spalte zu ORDER BY?

Also arbeite ich an einem Code Golf Puzzle und muss eine INT "Nummer" Spalte n zu einem Ergebnis hinzufügen, während Beibehaltung der aktuellen Reihenfolge.

Angenommen, meine Quelldaten sind:

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

dies gibt die Artikel in der ursprünglichen (gewünschten) Reihenfolge zurück:

value
-----
one
two
three
four
five

Wenn ich versuche, ROW_NUMBER() oder RANK() zu verwenden, muss ich einen ORDER BY Angeben, für den value die einzige legale Wahl ist:

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

Aber dies sortiert (wie erwartet) value alphabetisch, anstatt es in der gewünschten ursprünglichen Reihenfolge zu belassen:

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

Das Verknüpfen mit einer Zahlentabelle funktioniert nicht, da ich ohne eine WHERE -Klausel einen vollständigen äußeren Join erhalte.

Das Beste, was ich mir einfallen lassen konnte, war die Verwendung einer temporären Tabelle mit einem Identitätsfeld:

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

aber das ist wirklich lang und nervig. Irgendwelche besseren Ideen?

7
BradC

Der kanonische Weg, dies zu tun, ist der folgende: ROW_NUMBER() OVER(ORDER BY (SELECT NULL)). Wenn Sie Golf spielen, können Sie Folgendes ausprobieren:

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

Es funktioniert für den einfachen Fall, den Sie in der Frage gepostet haben:

(enter image description here

Ich sollte sagen, dass es keine dokumentierte Garantie dafür gibt, dass der Wert ROW_NUMBER() genau in der von Ihnen erwarteten Reihenfolge liegt. Aber es ist Code Golf, also scheint das gut genug zu sein.

10
Joe Obbish

Sie können sich nicht darauf verlassen, dass Ihre INSERTIDENTITY -Werte in der Reihenfolge Ihrer ursprünglichen Zeichenfolge generieren. Das ist vielleicht das, was Sie beobachten, aber das ist nur ein glücklicher Zufall und sicherlich nicht garantiert.

Folgendes funktioniert, wenn Sie keine Duplikate haben:

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;

Für Code Golf vielleicht:

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

Wenn Sie Duplikate haben, wird es viel komplexer. Einige Ideen hier vielleicht:

6
Aaron Bertrand

Eine andere Option ist die Verwendung einer Sequenz:

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', ',');

Ausgabe:

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

Es ist ärgerlich, dass STRING_SPLIT wurde ohne integrierte Nummerierungsoption implementiert. Stimmen Sie für Änderungen ab unter https://feedback.Azure.com/forums/908035-sql-server/suggestions/32902852-string-split-is-not-feature-complete

5
Paul White 9

Fügen Sie einfach eine weitere Alternative aus Ihrer Frage hinzu. Aber ich denke, die Bestellung ist nicht garantiert,

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