J'essaie de construire une seule instruction SQL qui renvoie des valeurs uniques non nulles à partir de plusieurs colonnes situées dans la même table.
SELECT distinct tbl_data.code_1 FROM tbl_data
WHERE tbl_data.code_1 is not null
UNION
SELECT tbl_data.code_2 FROM tbl_data
WHERE tbl_data.code_2 is not null;
Par exemple, tbl_data est la suivante:
id code_1 code_2
--- -------- ----------
1 AB BC
2 BC
3 DE EF
4 BC
Pour la table ci-dessus, la requête SQL doit renvoyer toutes les valeurs uniques non nulles des deux colonnes, à savoir: AB, BC, DE, EF.
Je suis assez nouveau pour SQL. Mon instruction ci-dessus fonctionne, mais existe-t-il une méthode plus propre pour écrire cette instruction SQL, puisque les colonnes proviennent de la même table?
Il est préférable d’inclure du code dans votre question plutôt que des données textuelles ambiguës, afin que nous travaillions tous avec les mêmes données. Voici l'exemple de schéma et de données que j'ai supposé:
CREATE TABLE tbl_data (
id INT NOT NULL,
code_1 CHAR(2),
code_2 CHAR(2)
);
INSERT INTO tbl_data (
id,
code_1,
code_2
)
VALUES
(1, 'AB', 'BC'),
(2, 'BC', NULL),
(3, 'DE', 'EF'),
(4, NULL, 'BC');
Comme Blorgbeard a commenté, la clause DISTINCT
dans votre solution est inutile car l'opérateur UNION
élimine les lignes en double. Il existe un opérateur UNION ALL
qui n'élimine pas les doublons, mais il n'est pas approprié ici.
La réécriture de votre requête sans la clause DISTINCT
est une bonne solution à ce problème:
SELECT code_1
FROM tbl_data
WHERE code_1 IS NOT NULL
UNION
SELECT code_2
FROM tbl_data
WHERE code_2 IS NOT NULL;
Peu importe que les deux colonnes soient dans la même table. La solution serait la même, même si les colonnes se trouvaient dans des tables différentes.
Si vous n'aimez pas la redondance de spécifier deux fois la même clause de filtre, vous pouvez encapsuler la requête d'union dans une table virtuelle avant de filtrer cela:
SELECT code
FROM (
SELECT code_1
FROM tbl_data
UNION
SELECT code_2
FROM tbl_data
) AS DistinctCodes (code)
WHERE code IS NOT NULL;
Je trouve la syntaxe de la seconde plus moche, mais c'est logiquement plus ordonné. Mais lequel fait mieux?
J'ai créé un sqlfiddle qui montre que l'optimiseur de requêtes de SQL Server 2005 produit le même plan d'exécution pour les deux requêtes différentes:
Si SQL Server génère le même plan d'exécution pour deux requêtes, celles-ci sont pratiquement aussi bien que logiquement équivalentes.
Comparez ce qui précède au plan d'exécution de la requête dans votre question:
La clause DISTINCT
oblige SQL Server 2005 à effectuer une opération de tri redondant, car l'optimiseur de requêtes ne sait pas que les doublons filtrés par DISTINCT
dans la première requête seront filtrés par UNION
ultérieurement.
Cette requête est logiquement équivalente aux deux autres, mais l'opération redondante la rend moins efficace. Sur un grand ensemble de données, je m'attendrais à ce que votre requête prenne plus de temps pour renvoyer un ensemble de résultats que les deux ici. Ne prenez pas ma parole pour cela; expérimentez dans votre propre environnement pour en être sûr!
essayez quelque chose comme SubQuery
:
SELECT derivedtable.NewColumn
FROM
(
SELECT code_1 as NewColumn FROM tbl_data
UNION
SELECT code_2 as NewColumn FROM tbl_data
) derivedtable
WHERE derivedtable.NewColumn IS NOT NULL
La UNION
renvoie déjà les valeursDISTINCTESde la requête combinée.
Essayez ceci si vous avez plus de deux colonnes CREATE TABLE #temptable (Nom1 VARCHAR (25), Nom2 VARCHAR (25))
INSERT INTO #temptable (Nom1, Nom2) VALEURS ('JON', 'Harry'), ('JON', 'JON'), ('Sam', 'harry')
SELECT t.Name1 + ',' + 't.Name2 Noms INTO #t FROM #temptable AS tSELECT DISTINCT ss.value FROM # t AS t CROSS APPLIQUER STRING_SPLIT (T.Names,', ') AS ss