2 votes

Requête Oracle pour compter les occurrences dans plusieurs colonnes

Je veux récupérer les clients qui ont effectué un total d'au moins 2 transactions basées sur trois colonnes. Y - Transaction réussie

EX:

Nom du client  Col1    Col2    Col3
Client1        Y       Y      N
Client2        N       N      Y
Client3        Y       Y      N

Pour le tableau ci-dessus, je veux afficher la sortie suivante (Je veux exclure le client qui n'a fait qu'une seule transaction)

Client1 - 2
Client3 - 2

1voto

Code Novice Points 397

Je vois que deux personnes ont répondu à votre question en utilisant des exemples agrégés. En effet, ils utilisent tous les deux GROUP BY et la clause HAVING. Vous n'avez pas nécessairement besoin d'utiliser un quelconque regroupement pour obtenir le résultat souhaité ici. Voici ci-dessous une solution alternative. C'est peut-être simplement une opinion, mais je préfère cette solution :

WITH demo_data (cname, col1, col2, col3) AS
( /* Utilisation de CTE pour produire une fausse table avec des données */
  SELECT 'cust1', 'Y', 'Y', 'N' FROM dual UNION ALL
  SELECT 'cust2', 'N', 'N', 'Y' FROM dual UNION ALL
  SELECT 'cust3', 'Y', 'N', 'Y' FROM dual UNION ALL
  SELECT 'cust4', 'Y', 'Y', 'Y' FROM dual UNION ALL
  SELECT 'cust5', 'Y', 'Y', 'N' FROM dual UNION ALL
  SELECT 'cust6', 'Y', 'N', 'N' FROM dual
)
, transform_data AS
( /* Utilisation de decode pour convertir tous les 'Y' et 'N' en nombres */
  SELECT cname
       , decode(col1, 'Y', 1, 0) AS col1
       , decode(col2, 'Y', 1, 0) AS col2
       , decode(col3, 'Y', 1, 0) AS col3
  FROM demo_data
)
/* Maintenant nous avons créé notre colonne SUM en utilisant les colonnes 1 à 3 */
SELECT cname, col1, col2, col3
  /* Je n'avais pas besoin de créer la colonne sum_col mais je l'ai ajoutée à des fins visuelles */
  , col1 + col2 + col3 AS sum_col
FROM transform_data
WHERE col1 + col2 + col3 > 1
;

Capture d'écran de la sortie pour chacune des tables produites par la clause WITH et la sortie désirée réelle.

entrez la description de l'image ici

0voto

âńōŋŷXmoůŜ Points 3644

Vous pouvez combiner la clause SUM() et HAVING().

SELECT Customer_Name,
SUM(CASE WHEN Col1='Y' then 1 else 0 end)+
SUM(CASE WHEN Col2='Y' then 1 else 0 end)+
SUM(CASE WHEN Col3='Y' then 1 else 0 end) as total
FROM myTable
GROUP BY Customer_Name
HAVING SUM(CASE WHEN Col1='Y' then 1 else 0 end)+
SUM(CASE WHEN Col2='Y' then 1 else 0 end)+
SUM(CASE WHEN Col3='Y' then 1 else 0 end)=2

    Résultat:
    CUSTOMER_NAME   TOTAL
    Customer3        2
    Customer1        2

0voto

Littlefoot Points 34537

Quelque peu similaire au code de @anonyXmous, mais en utilisant DECODE et pas autant de SUMs (inutiles?) :

SQL> with test (cname, col1, col2, col3) as
  2    (select 'cust1', 'y', 'y', 'n' from dual union
  3     select 'cust2', 'n', 'n', 'y' from dual union
  4     select 'cust3', 'y', 'n', 'y' from dual
  5    )
  6  select cname,
  7    sum(decode(col1, 'y', 1, 0) +
  8        decode(col2, 'y', 1, 0) +
  9        decode(col3, 'y', 1, 0)) sumc
 10  from test
 11  group by cname
 12  having sum(decode(col1, 'y', 1, 0) +
 13             decode(col2, 'y', 1, 0) +
 14             decode(col3, 'y', 1, 0)) >= 2
 15  order by cname;

CNAME       SUMC
----- ----------
cust1          2
cust3          2

SQL>

0voto

Thorsten Kettner Points 6149

De ce que vous montrez, il semble :

  • Que vous avez une table avec trois colonnes booléennes. Comme le SGBD Oracle ne propose toujours pas le type de données booléen, vous avez utilisé col1 CHAR(1) NOT NULL, CONSTRAINT chk_customers_bool_col1 CHECK (col1 in ('Y','N')) etc. à la place. (Dommage qu'Oracle nous oblige à appliquer de tels contournements.)
  • Que vous montrez une table de clients avec un enregistrement par client et trois attributs, que vous appelez col1, col2, col3 dans votre exemple, mais qui sont des attributs réels dans la vraie vie, tels que rapide, sympathique, riche, et vous voulez sélectionner les clients pour lesquels au moins deux des attributs sont vrais.

Une méthode simple pour réaliser cela serait de concaténer les trois lettres, supprimer les Ns et compter les Ys restants.

select
  Nom_Client, 
  length(replace(col1 || col2 ||| col3 ,'N',''))
from customers
where length(replace(col1 || col2 ||| col3 ,'N','')) >= 2;

Cette requête fonctionne toujours pour les booléens à trois états (c'est-à-dire avec null autorisé), mais pas si les colonnes peuvent contenir d'autres caractères (comme 'M' pour "peut-être" ou 'S' pour "parfois"). Dans ce cas, vous devriez utiliser une expression CASE ou le DECODE d'Oracle pour vérifier les Ys.


Beaucoup de gens préfèrent les nombres 0 et 1 pour émuler le faux et vrai booléens dans Oracle. Un avantage par rapport à 'N' et 'Y' est que vous pouvez rapidement les ajouter pour compter combien sont vrais, ce qui correspond exactement à votre cas. (Dans MySQL où un type de données booléen existe, ils vont même jusqu'à permettre de faire des mathématiques avec eux en remplaçant faux par 0 et vrai par 1, donc vrai + faux + vrai = 2.)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X