2017-04-26 3 views
1

Ich wurde gebeten, zu versuchen, eine count() Abfrage zu vereinfachen, aber ich weiß nicht, wo man anfangen soll, ist die Abfrage etwas wie folgt aus:Oracle Wie vereinfacht man eine Auswahl zählen (*) von (Unterabfrage)?

SELECT COUNT(1) 
FROM (
     SELECT DISTINCT a.col,b.colx,c.coly 
     FROM a 
      JOIN b on a.id = b.id 
      JOIN c on b.id = c.id 
     WHERE a.xyz = 'something' 
     AND b.hijk = 'something else' 
     AND c.id IN (
       SELECT cid 
       FROM cwa 
       WHERE csid = 22921 
      ) 
     ORDER BY 
      e.create_timestamp DESC 
    ); 

Mir wurde gesagt, dass die SELECT COUNT(1) FROM (subquery) vereinfacht werden kann, wie dies getan werden kann ?

Ich habe ein paar Dinge ausprobiert, aber das Ergebnis unterscheidet sich von der obigen Abfrage.

+5

Hint erhöhen: Durch die Bestellung kann entfernt werden; Außerdem benötigen Sie keine Abfrage über eine Abfrage – Aleksej

Antwort

4

Eine order-by in einer Unterabfrage ist nicht nützlich, es sei denn, Sie filtern das Ergebnis nach rownum (und manchmal wird je nach Kontext ein Fehler). Und Sie können die innere Unterabfrage mit einem Ersatz kommen:

SELECT COUNT(*) 
FROM (
    SELECT DISTINCT a.col,b.colx,c.coly 
    FROM a 
    JOIN b on a.id = b.id 
    JOIN c on b.id = c.id 
    JOIN cwa on c.id cwa.cid 
    WHERE a.xyz = 'something' 
    AND b.hijk = 'something else' 
    AND cwa.csid = 22921 
); 

Sie könnten es sogar tun, ohne eine Unterabfrage, wenn Sie ein Zeichen identifizieren, die nicht in eine der drei Spalten angezeigt werden Sie die Auswahl, so dass Sie kann es als Trennzeichen verwenden; z.B. wenn Sie nie eine Tilde haben könnten Sie tun:

SELECT COUNT(DISTINCT a.col ||'~'|| b.colx ||'~'|| c.coly) 
FROM a 
JOIN b on a.id = b.id 
JOIN c on b.id = c.id 
JOIN cwa on c.id cwa.cid 
WHERE a.xyz = 'something' 
AND b.hijk = 'something else' 
AND cwa.csid = 22921; 

obwohl, ob die einfache oder klare Ansichtssache ist.


Als count() nur ein einziges Argument nimmt, und Sie möchten die (unterschiedlichen) Kombinationen dieser drei Spalten zählen, verkettet dieser Mechanismus alle drei in einem einzelnen String und zählt dann Erscheinungen dieser Zeichenfolge. Das Trennzeichen hinzugefügt wird, so dass Sie zwischen mehrdeutigen Spaltenwerten, beispielsweise mit einem konstruiertes Beispiel in einem WAK unterscheiden:

with cte (col1, col2) as (
    select 'The', 'search' from dual 
    union all select 'These', 'arch' from dual 
) 
select col1, col2, 
    col1 || col2 as bad, 
    col1 ||'~'|| col2 as good 
from cte; 

COL1 COL2 BAD   GOOD   
----- ------ ----------- ------------ 
The search Thesearch The~search 
These arch Thesearch These~arch 

Mit einfacher ‚schlechter‘ Verkettung beiden Reihen erscheinen gleich; durch die Begrenzer Hinzufügen die ‚gute‘ Version, damit Sie sich immer noch zwischen ihnen unterscheiden können, so zählen verschiedene concatenate Werte bekommt die richtige Antwort:

with cte (col1, col2) as (
    select 'The', 'search' from dual 
    union all select 'These', 'arch' from dual 
) 
select count(distinct col1 || col2) as bad_count, 
    count (distinct col1 ||'~'|| col2) as good_count 
from cte; 

BAD_COUNT GOOD_COUNT 
---------- ---------- 
     1   2 

Wenn col1 mit einer Tilde beendet oder col2 mit einer Tilde gestartet, Sie Würd zu Mehrdeutigkeit sein:

with cte (col1, col2) as (
    select 'The~', 'search' from dual 
    union all select 'The', '~search' from dual 
) 
select col1, col2, 
    col1 || col2 as bad, 
    col1 ||'~'|| col2 as still_bad 
from cte; 

COL1 COL2 BAD   STILL_BAD 
---- ------- ----------- ------------ 
The~ search The~search The~~search 
The ~search The~search The~~search 

so muss der Begrenzer etwas sein, werden Sie nicht in irgendwelchen Werten finden.

+0

@shep - Ich habe eine kurze Demo hinzugefügt, warum das Trennzeichen benötigt wird, hoffe, dass das klarer ist. –

+0

Gute Antwort, großartige Erklärung – unleashed

0

Try

SELECT count(DISTINCT a.col) 
    FROM a 
     JOIN b on a.id = b.id 
     JOIN c on b.id = c.id 
    WHERE a.xyz = 'something' 
    AND b.hijk = 'something else' 
    AND c.id IN (
      SELECT cid 
      FROM cwa 
      WHERE csid = 22921 
     ); 

Da Reihenfolge durch die Verwendung Ihrer Ausführungszeit unnötig