Je travaille donc sur un code golf puzzle et j'ai besoin d'ajouter une colonne INT "nombre" n à un résultat tout en maintenir l'ordre actuel.
Disons que mes données source sont:
SELECT value
FROM STRING_SPLIT('one,two,three,four,five', ',')
qui renvoie les articles dans l'ordre d'origine (souhaité):
value
-----
one
two
three
four
five
Si j'essaie d'utiliser ROW_NUMBER()
ou RANK()
je suis obligé de spécifier un ORDER BY
, Pour lequel value
est le seul choix légal:
SELECT value, n = ROW_NUMBER() OVER(ORDER BY value)
FROM STRING_SPLIT('one,two,three,four,five',',')
Mais cela (comme prévu) trie value
par ordre alphabétique au lieu de le laisser dans l'ordre d'origine souhaité:
value n
------ ---
five 1
four 2
one 3
three 4
two 5
La jointure à une table numérique ne fonctionne pas, car sans clause WHERE
, j'obtiendrai une jointure externe complète.
Le mieux que j'ai pu trouver était d'utiliser une table temporaire avec un champ d'identité:
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
mais c'est vraiment long et ennuyeux. De meilleures idées?
La manière canonique de procéder est la suivante: ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
. Si vous jouez au golf, vous pouvez essayer quelque chose comme ceci:
SELECT value, n = ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM STRING_SPLIT('one,two,three,four,five',',')
Cela fonctionne pour le cas simple que vous avez publié dans la question:
Je dois dire qu'il n'y a aucune garantie documentée que la valeur de ROW_NUMBER()
sera dans l'ordre précis que vous attendez. Mais c'est du golf de code, donc cela semble suffisant.
Vous ne pouvez pas compter sur vos INSERT
pour générer des valeurs de IDENTITY
dans l'ordre de votre chaîne d'origine. C'est peut-être ce que vous observez, mais ce n'est qu'une coïncidence chanceuse et certainement pas garantie.
Les éléments suivants fonctionneront si vous n'avez pas de doublons:
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;
Pour le code golf peut-être:
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
Si vous avez des doublons, cela devient beaucoup plus complexe. Quelques idées ici peut-être:
Une autre option consiste à utiliser une séquence:
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', ',');
Production:
╔═══════╦═══╗
║ one ║ 1 ║
║ two ║ 2 ║
║ three ║ 3 ║
║ four ║ 4 ║
║ five ║ 5 ║
╚═══════╩═══╝
Il est ennuyeux que STRING_SPLIT
a été implémenté sans option de numérotation intégrée. Votez pour le changement sur https://feedback.Azure.com/forums/908035-sql-server/suggestions/32902852-string-split-is-not-feature-complete
Il suffit d'ajouter une autre alternative à votre question. Mais je pense que la commande n'est pas garantie,
SELECT value v,IDENTITY(INT,1,1) AS n
INTO #argg
FROM STRING_SPLIT('one,two,three,four,five',',')
SELECT * FROM #argg