web-dev-qa-db-fra.com

SQL en utilisant CASE dans SELECT avec GROUP BY. Besoin de CASE-value mais get-row

donc, fondamentalement, il y a 1 question et 1 problème:

1. question - lorsque j'ai environ 100 colonnes dans une table (et qu'aucune clé ou uindex n'est définie) et que je souhaite rejoindre ou sous-sélectionner cette table avec elle-même, dois-je vraiment écrire chaque nom de colonne?

2. problème - l'exemple ci-dessous montre la 1. question et mon problème d'instruction SQL 

Exemple:

A.FIELD1,
(SELECT CASE WHEN B.FIELD2 = 1 THEN B.FIELD3 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD1
(SELECT CASE WHEN B.FIELD2 = 2 THEN B.FIELD4 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD2
FROM TABLE A
GROUP BY A.FIELD1

L’histoire est la suivante: si je ne mets pas le CASE dans sa propre instruction select, je dois alors mettre le nom réel dans GROUP BY et le GROUP BY ne regroupe pas la valeur NULL du CASE, mais la valeur réelle du rangée. Et à cause de cela, je devrais soit rejoindre ou sous-sélectionner avec toutes les colonnes, car il n'y a pas de clé et pas d'index, ou en quelque sorte trouver une autre solution.

DBServer est DB2.

Alors maintenant, décrivant simplement avec des mots et pas de SQL: J'ai des "articles de commande" qui peuvent être divisés en "ZD" et "EK" (1 = ZD, 2 = EK) et peuvent être regroupés par " distributeur". Même si les "articles de commande" peuvent avoir l'un des deux "départements" (ZD, EK) différents, les champs/lignes de "ZD" et "EK" sont toujours remplis. J'ai besoin que le groupement considère le "département" et que si le "département" désigné (ZD ou EK) est en train de changer, je souhaite qu'un nouveau groupe soit créé.

SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
ZD
EK
TABLE.DISTRIBUTOR
TABLE.DEPARTEMENT

Cela a fonctionné ici dans les SELECT et ZD, EK dans GROUP BY. Le seul problème était que, même si EK n'était pas désigné par DEPARTEMENT, il ouvrait quand même un nouveau groupe s'il changeait, car il utilisait la valeur réelle d'EK et non la valeur NULL de CASE, comme je l'expliquais déjà en haut.

9
Khazar

Et voici, mesdames et messieurs, la solution au problème:

SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END),
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END),
TABLE.DISTRIBUTOR,
TABLE.DEPARTEMENT

@ t-clausen.dk: Merci!

@autres: ...

7
Khazar

En fait, il existe un test d’égalité avec caractère générique Je ne vois pas trop pourquoi vous regrouperiez par champ1, cela semblerait impossible dans votre exemple. J'ai essayé de l'intégrer dans votre question:

SELECT FIELD1,
CASE WHEN FIELD2 = 1 THEN FIELD3 END AS CASEFIELD1,
CASE WHEN FIELD2 = 2 THEN FIELD4 END AS CASEFIELD2
FROM 
(
 SELECT * FROM A
 INTERSECT
 SELECT * FROM B
) C
UNION -- results in a distinct
SELECT
A.FIELD1,
null,
null
FROM 
(
 SELECT * FROM A
 EXCEPT
 SELECT * FROM B
) C

Cela échouera pour les types de données qui ne sont pas comparables

2
t-clausen.dk

Je pourrais avoir tendance à résoudre quelque chose comme ça

WITH q as
(SELECT
       Department
     , (CASE WHEN DEPARTEMENT = 1 THEN ZD
             WHEN DEPARTEMENT = 2 THEN EK
                                  ELSE null 
        END) AS GRP
     , DISTRIBUTOR
     , SOMETHING 
   FROM mytable
)
SELECT 
       Department
     , Grp
     , Distributor

     , sum(SOMETHING) AS SumTHING
  FROM q
GROUP BY
       DEPARTEMENT 
     , GRP
     , DISTRIBUTOR
1
WarrenT

Non, il n'y a pas de test d'égalité générique. Vous devez répertorier chaque champ que vous souhaitez tester individuellement. Si vous ne souhaitez pas tester chaque champ individuel, vous pouvez utiliser un hack, par exemple en concaténant tous les champs, par exemple.

WHERE (a.foo + a.bar + a.baz) = (b.foo + b.bar + b.az)

mais de toute façon, vous listez tous les champs.

1
Marc B

Si vous devez rechercher toutes les lignes dans TableA qui correspondent dans TableB, que diriez-vous d'INTERSECT ou d'INTERSECT DISTINCT?

select * from A
 INTERSECT DISTINCT
select * from B

Toutefois, si vous souhaitez uniquement des lignes de A dont la ligne entière correspond aux valeurs d'une ligne de B, pourquoi votre exemple de code utilise-t-il des valeurs de A et d'autres de B? Si la ligne correspond à toutes les colonnes, cela semblerait inutile. (Peut-être que votre question pourrait être un peu plus expliquée?)

0
WarrenT