2016-04-08 10 views
0

benötigen Hilfe bei einer komplizierten Abfrage. Dies ist ein Auszug aus meinem Tisch:Oracle XE, zählen und zeigen verschiedene Kombinationen von Zeilen basierend auf einer Spalte

USERID SERVICE 
1   A 
1   B 
2   A 
3   A 
3   B 
4   A 
4   C 
5   A 
6   A 
7   A 
7   B 

Ok, würde ich die Abfrage alle möglichen Kombinationen zurückkehren möge und anzuzeigen, die mit ihren jeweiligen Zählungen in meiner Tabelle existieren auf der Basis der Service-Spalte. Zum Beispiel hat der erste Benutzer A- und B-Service, dies ist eine Kombination, die einmal aufgetreten ist. Der nächste Benutzer hat nur den Dienst A, dies ist eine weitere Kombination, die einmal aufgetreten ist. Drittens Benutzer hat Service A und B, hat dies schon einmal passiert ist, und die Zählung für diese Kombination ist 2 jetzt usw. Also meine Ausgabe basierend auf diesem speziellen Eingang eine Tabelle wie folgt sein würde:

A AB AC ABC B BC 
3 3 1 0 0 0 

So zu klären ein bisschen mehr, wenn es 3 Dienste gibt, dann gibt es 3! mögliche Kombinationen; 3x2x1 = 6 und sie sind A, B, C, AB, AC, BC und ABC. Und meine Tabelle sollte die Anzahl der Benutzer enthalten, denen diese Kombination von Diensten zugewiesen wurde.

Ich habe versucht, den Aufbau einer Matrix diese Abfrage verwenden und dann alle, zählt die CUBE-Funktion:

select service_A, service_B, service_C from 
    (select USERID, 
    max(case when SERVICE =A then 1 else null end) service_A, 
    max(case when SERVICE =B then 1 else null end) service_B, 
    max(case when SERVICE =C then 1 else null end) service_C 
    from SOME_TABLE) 
group by CUBE(service_A, service_B,service_C); 

Aber ich habe nicht die Anzahl aller Kombinationen erhalten. Ich brauche nur Kombinationen, die passiert sind, also zählt 0 ist nicht notwendig, aber es ist in Ordnung, sie anzuzeigen. Vielen Dank.

+0

Sie haben eine Reihe von möglichen Kombinationen? Das heißt, wissen Sie im Voraus, wie viele Spalten Ihre Abfrage zurückgeben wird? Wenn nicht, können Sie es nicht mit einer einfachen Abfrage tun, aber Sie brauchen etwas Dynamisches (und dann kann es schwierig sein, eine Ergebnismenge mit einer unbekannten Anzahl von Spalten zu behandeln) – Aleksej

+0

Ich weiß, welche Dienste zur Verfügung stehen, zum Beispiel gibt es 10 Dienstleistungen, die eine Person haben kann. So ist es möglich, die Berechnung zu machen und zu finden, dass es 10 gibt! Anzahl der verschiedenen Kombination von Dienstleistungen, die eine große Anzahl ist. Das wäre also die maximale Anzahl der Spalten. Aber die meisten von ihnen werden zählen 0, das Problem ist, ich weiß nicht welche, also muss ich alles berechnen. – Hrvoje85

Antwort

2

Geben Sie es nicht als dynamische Spalten aus (es ist schwierig ohne PL/SQL und dynamisches SQL), sondern geben Sie es als Zeilen aus (wenn Sie ein Frontend haben, kann es normalerweise Zeilen in Spalten übersetzen) einfacher als Orakel kann):

Oracle-Setup:

CREATE TABLE some_table (USERID, SERVICE) AS 
SELECT 1, 'A' FROM DUAL UNION ALL 
SELECT 1, 'B' FROM DUAL UNION ALL 
SELECT 2, 'A' FROM DUAL UNION ALL 
SELECT 3, 'A' FROM DUAL UNION ALL 
SELECT 3, 'B' FROM DUAL UNION ALL 
SELECT 4, 'A' FROM DUAL UNION ALL 
SELECT 4, 'C' FROM DUAL UNION ALL 
SELECT 5, 'A' FROM DUAL UNION ALL 
SELECT 6, 'A' FROM DUAL UNION ALL 
SELECT 7, 'A' FROM DUAL UNION ALL 
SELECT 7, 'B' FROM DUAL; 

Abfrage:

SELECT service, 
     COUNT(userid) AS num_users 
FROM (
    SELECT userid, 
     LISTAGG(service) WITHIN GROUP (ORDER BY service) AS service 
    FROM some_table 
    GROUP BY userid 
) 
GROUP BY service; 

Ausgang:

SERVICE NUM_USERS 
------- ---------- 
AC    1 
A    3 
AB    3 

PL/SQL für dynamische Spalten:

VARIABLE cur REFCURSOR; 

DECLARE 
    TYPE string_table IS TABLE OF VARCHAR2(4000); 
    TYPE int_table IS TABLE OF INT; 
    t_services string_table; 
    t_counts int_table; 
    p_sql  CLOB; 
BEGIN 
    SELECT service, 
     COUNT(userid) AS num_users 
    BULK COLLECT INTO t_services, t_counts 
    FROM (
    SELECT userid, 
      CAST(LISTAGG(service) WITHIN GROUP (ORDER BY service) AS VARCHAR2(2)) AS service 
    FROM some_table 
    GROUP BY userid 
) 
    GROUP BY service; 

    p_sql := EMPTY_CLOB() || 'SELECT '; 
    p_sql := p_sql || t_counts(1) || ' AS "' || t_services(1) || '"'; 
    FOR i IN 2 .. t_services.COUNT LOOP 
    p_sql := p_sql || ', ' || t_counts(i) || ' AS "' || t_services(i) || '"'; 
    END LOOP; 
    p_sql := p_sql || ' FROM DUAL'; 

    OPEN :cur FOR p_sql; 
END; 
/

PRINT cur; 

Ausgang:

AC A AB 
--- --- --- 
1 3 3 
+0

Wow, danke für die schnelle und genaue Antwort, das ist genau das, was ich wollte !!!! – Hrvoje85