2017-05-18 7 views
0

Ich habe eine Tabelle wie folgt aus:Wie gruppieren eindeutige Tags in Oracle SQL?

GROUPID | TAG 
------ | ------ 
1  | Tag1 Tag2 
1  | Tag1 Tag3 
1  | Tag1 Tag4 
2  | Tag5 Tag6 
2  | Tag4 Tag3 

Und ich möchte die folgenden Ergebnisse erhalten:

GROUP | TAG 
------- | ------- 
1  | Tag1 Tag2 Tag3 Tag4 
2  | Tag3 Tag4 Tag5 Tag6 

Und Ideen, wie die duplizierten-Tags in Oracle SQL filtern?

Dank

+2

Schlechte Idee rundherum. Was bedeutet "Ich habe" - ist die Eingabedaten (Ihre erste Tabelle) eine gespeicherte Tabelle, auf der Festplatte? Was bedeutet "Ergebnis" - was wird für die Berichterstattung angezeigt? Wenn dies der Fall ist, ist der Bericht in diesem Format möglicherweise in Ordnung, aber die Basisdaten verletzen eines der grundlegendsten Prinzipien des Designs relationaler Tabellen. So grundlegend, dass es "Erste Normalform" genannt wird. Die beste Lösung in all diesen Fällen ist, Ihre Daten zu normalisieren - wenn Sie nicht in der Datenbank, dann zumindest in Ihrer Abfrage. – mathguy

+0

Jack haben Ihre Daten immer zwei Tags pro GroupId pro Zeile oder eine beliebige Anzahl von Tags pro Zeile? – alexgibbs

+0

wäre es irgendwelche Tags pro Zeile. Und es könnte auch leer sein. Vielen Dank. -Jack – user3595231

Antwort

1

Wie mathguy in den Kommentaren erwähnt, Abfragen wie diese können durch Änderungen an der Konstruktion vereinfacht werden.
Aber angesichts der Daten in diesem Format kann man immer noch einen eindeutigen Satz von TAG per GROUPID extrahieren. Hier ist ein Beispiel Ansatz:

In dieser ersten Stufe werden wir REGEXP_COUNT verwenden, um zu sehen, wie viele TAG s jede Zeile hat. Dann werden wir erzeugen Positions-Tag-Nummern für jede TAG in jeder Zeile. Schließlich extrahieren wir das Tag an einer bestimmten Position für jedes Konglomerat TAG in jeder Zeile.

Erstellen Sie zunächst die Testtabelle:

CREATE TABLE GROUPID_TAG(
    GROUPID NUMBER, 
    "TAG" VARCHAR2(256) 
); 

INSERT INTO GROUPID_TAG VALUES (1,'Tag1 Tag2'); 
INSERT INTO GROUPID_TAG VALUES (1,'Tag1 Tag3'); 
INSERT INTO GROUPID_TAG VALUES (1,'Tag1 Tag4'); 
INSERT INTO GROUPID_TAG VALUES (2,'Tag5 Tag6'); 
INSERT INTO GROUPID_TAG VALUES (2,'Tag4 Tag3'); 

Die folgende Abfrage zwei Spalten, mit einer einzigen TAG in den ONLY_ONE_TAG Spalt erzeugen (aber mehr Zeilen pro GROUPID)

WITH COUNTED_TAG AS (
    SELECT GROUPID, "TAG", REGEXP_COUNT("TAG",'(^|)[^ ]{1,}') AS TAG_COUNT FROM GROUPID_TAG), 
    KEYED_COUNTED_TAG AS (
    SELECT GROUPID, "TAG", TAG_COUNT, TAG_KEG_GENERATOR.TAG_KEY FROM COUNTED_TAG 
     INNER JOIN (SELECT LEVEL AS TAG_KEY FROM DUAL CONNECT BY LEVEL <= 999) TAG_KEG_GENERATOR 
     ON TAG_KEG_GENERATOR.TAG_KEY <= COUNTED_TAG.TAG_COUNT) 
SELECT DISTINCT GROUPID, REPLACE(REGEXP_SUBSTR("TAG",'(^|)[^ ]{1,}',1,TAG_KEY),' ','') AS ONLY_ONE_TAG 
FROM KEYED_COUNTED_TAG 
ORDER BY 1 ASC, 2 ASC; 

es Laufen gibt:

GROUPID ONLY_ONE_TAG 
1  Tag1   
1  Tag2   
1  Tag3   
1  Tag4   
2  Tag3   
2  Tag4   
2  Tag5   
2  Tag6  

Die Daten an dieser Stelle sind möglicherweise einfacher zu bearbeiten als im ursprünglichen Zustand. Aber wenn Sie pro GROUPID in einer Zeile aggregieren möchten, ist hier ein Beispiel dafür. Beginnend mit unserem letzten Abfrage werden wir eine LISTAGG zu aggregieren Dinge hinzufügen:

WITH COUNTED_TAG AS (
    SELECT GROUPID, "TAG", REGEXP_COUNT("TAG",'(^|)[^ ]{1,}') AS TAG_COUNT FROM GROUPID_TAG), 
    KEYED_COUNTED_TAG AS (
    SELECT GROUPID, "TAG", TAG_COUNT, TAG_KEG_GENERATOR.TAG_KEY FROM COUNTED_TAG 
     INNER JOIN (SELECT LEVEL AS TAG_KEY FROM DUAL CONNECT BY LEVEL <= 999) TAG_KEG_GENERATOR 
     ON TAG_KEG_GENERATOR.TAG_KEY <= COUNTED_TAG.TAG_COUNT), 
    DISTINCT_TAG AS(SELECT DISTINCT GROUPID, REPLACE(REGEXP_SUBSTR("TAG",'(^|)[^ ]{1,}',1,TAG_KEY),' ','') AS ONLY_ONE_TAG 
        FROM KEYED_COUNTED_TAG) 
SELECT GROUPID, LISTAGG(ONLY_ONE_TAG,' ') WITHIN GROUP (ORDER BY ONLY_ONE_TAG ASC) AS AGGREGATED_TAG 
FROM DISTINCT_TAG 
GROUP BY GROUPID 
ORDER BY 1 ASC; 

Ergebnis:

GROUPID AGGREGATED_TAG  
1  Tag1 Tag2 Tag3 Tag4 
2  Tag3 Tag4 Tag5 Tag6 

Dann fügen Sie einige zusätzliche Tags, für die Prüfung:

INSERT INTO GROUPID_TAG VALUES (1,'Wookie Hobbit @[email protected]'); 
INSERT INTO GROUPID_TAG VALUES (2,'HAL-9000 Thor'); 

Und Abfrage erneut:

WITH COUNTED_TAG AS (
    SELECT GROUPID, "TAG", REGEXP_COUNT("TAG",'(^|)[^ ]{1,}') AS TAG_COUNT FROM GROUPID_TAG), 
    KEYED_COUNTED_TAG AS (
    SELECT GROUPID, "TAG", TAG_COUNT, TAG_KEG_GENERATOR.TAG_KEY FROM COUNTED_TAG 
     INNER JOIN (SELECT LEVEL AS TAG_KEY FROM DUAL CONNECT BY LEVEL <= 999) TAG_KEG_GENERATOR 
     ON TAG_KEG_GENERATOR.TAG_KEY <= COUNTED_TAG.TAG_COUNT), 
    DISTINCT_TAG AS(SELECT DISTINCT GROUPID, REPLACE(REGEXP_SUBSTR("TAG",'(^|)[^ ]{1,}',1,TAG_KEY),' ','') AS ONLY_ONE_TAG 
        FROM KEYED_COUNTED_TAG) 
SELECT GROUPID, LISTAGG(ONLY_ONE_TAG,' ') WITHIN GROUP (ORDER BY ONLY_ONE_TAG ASC) AS AGGREGATED_TAG 
FROM DISTINCT_TAG 
GROUP BY GROUPID 
ORDER BY 1 ASC; 

Ergebnis:

GROUPID AGGREGATED_TAG       
1  @[email protected] Hobbit Tag1 Tag2 Tag3 Tag4 Wookie 
2  HAL-9000 Tag3 Tag4 Tag5 Tag6 Thor  
+0

Danke. Aber irgendwie wird diese SQL – user3595231

+0

Danke @ user3595231 Es sieht aus wie Ihr Kommentar abgeschnitten. Meinst du, dass sql nicht für dich ausgeführt wird? Welche Version von Oracle verwenden Sie? Können Sie die Ausnahme einschließen, die Sie erhalten? Danke – alexgibbs

+0

Wenn der TAG in GROUPID_TAG TABLE mehr als 2 TAGS enthält, sehe ich einige seltsame Ergebnisse. Dies ist, was ich hinzugefügt habe "INSERT IN GROUPID_TAG VALUES (2, 'AAA BBB CCC DDD'); COMMIT", Und die SQL ausgeführt, das Ergebnis gab mir nur einen Teil der TAGS für "2" Group. -Jack. – user3595231