J'ai quatre arrays, le Table A
, le Table B
, le Table C
et le Table D
Le schéma des quatre tables est identique. J'ai besoin d' union
ces quatre tables de la façon suivante:
Si un logging est présent dans le Table A
cela est pris en count dans la table de sortie.
Si un logging est présent dans le Table B
il est considéré dans la table de sortie SEULEMENT s'il n'est pas présent dans le Table A
Si un logging est présent dans le Table C
alors il est considéré UNIQUEMENT s'il n'est pas présent dans les Table A
et Table B
Si un logging est présent dans le Table D
alors il est considéré UNIQUEMENT s'il n'est pas présent dans le Table A
, le Table B
et le Table C
Remarque –
Chaque table a une colonne qui identifie la table elle-même pour chaque logging (je ne sais pas si c'est important)
Les loggings sont identifiés en fonction d'une colonne particulière – Column X
qui n'est pas unique même dans chaque table
Vous pourriez faire quelque chose comme (seulement deux cas montrés mais vous devriez voir comment l'étendre)
WITH CTE1 AS ( SELECT 't1' as Source, X, Y FROM t1 UNION ALL SELECT 't2' as Source, X, Y FROM t2 ), CTE2 AS ( SELECT *, RANK() OVER (PARTITION BY X ORDER BY CASE Source WHEN 't1' THEN 1 WHEN 't2' THEN 2 END) As RN FROM CTE1 ) SELECT X,Y FROM CTE2 WHERE RN=1
Je serais enclin à le faire en utilisant not exists
:
select a.* from a union all select b.* from b where not exists (select 1 from a where ax = bx) union all select c.* from c where not exists (select 1 from a where ax = cx) and not exists (select 1 from b where bx = cx) union all select d.* from d where not exists (select 1 from a where ax = dx) and not exists (select 1 from b where bx = dx) and not exists (select 1 from c where cx = dx);
Si vous avez un index sur la colonne x
dans chaque table, cela devrait être la méthode la plus rapide.
Cela fonctionnera tant qu'il n'y a pas de colonnes NULL, ou si les colonnes d'un logging existant dans une table avec une priorité supérieure sont NULL, vous pouvez supposer que la même colonne sera NULL dans les tables de priorité inférieure.
SELECT coalesce(a.column1, b.column1, c.column1, d.column1) column1 ,coalesce(a.column2, b.column2, c.column2, d.column2) column2 ,coalesce(a.column3, b.column3, c.column3, d.column3) column3 --... ,coalesce(a.columnN, b.columnN, c.columnN, d.columnN) columnN FROM TableA a FULL JOIN TableB b on b.ColumnX = a.ColumnX FULL JOIN TableC c on c.ColumnX = a.ColumnX or c.ColumnX = b.ColumnX FULL JOIN TableD d on d.ColumnX = a.ColumnX or d.ColumnX = b.ColumnX or d.ColumnX = c.ColumnX
Si les valeurs NULL sont importantes, vous pouvez passer à une version CASE plus compliquée (et probablement plus lente):
CASE WHEN a.columnX IS NOT NULL THEN a.column1 WHEN b.columnX IS NOT NULL THEN b.column1 WHEN c.columnX IS NOT NULL THEN c.column1 WHEN d.columnX IS NOT NULL THEN d.column1 END column1
Bien sûr, vous pouvez mélanger et faire correspondre, donc les colonnes qui ne sont pas valables peuvent utiliser la syntaxe précédente, et les colonnes où les valeurs NULL sont importantes utilisent la dernière.
Espérons que le but de ceci est de réparer le schéma brisé et de mettre toutes ces données dans la même table, où elles appartiennent.
Cela peut sembler stupide, mais si, par hasard, vous pouvez omettre la colonne d'identification de la table et que vous voulez également éliminer les loggings en double (d'une table), la réponse la plus simple serait
select <all columns without table identifier> from tableA union select <all columns without table identifier> from tableB union select <all columns without table identifier> from tableC ...
C'est exactement ce que l' union
été conçue pour faire: append des lignes seulement si elles n'existent pas auparavant.