Frage

Ich bin neu mit analytischen Funktionen zu arbeiten.

DEPT EMP   SALARY
---- ----- ------
  10 MARY  100000
  10 JOHN  200000
  10 SCOTT 300000
  20 BOB   100000
  20 BETTY 200000
  30 ALAN  100000
  30 TOM   200000
  30 JEFF  300000

Ich möchte die Abteilung und Mitarbeiter mit Mindestlohn.

Die Ergebnisse sollen wie folgt aussehen:

DEPT EMP   SALARY
---- ----- ------
  10 MARY  100000
  20 BOB   100000
  30 ALAN  100000

EDIT: Hier ist die SQL Ich habe (aber natürlich, es nicht funktioniert, wie es will Mitarbeiter in der Gruppe durch Klausel als auch):

SELECT dept, 
  emp,
  MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary)
FROM mytable
GROUP BY dept
War es hilfreich?

Lösung

Ich denke, dass die Rang () Funktion ist nicht der Weg mit diesem zu gehen, aus zwei Gründen.

Zum einen ist es wahrscheinlich weniger effizient als ein Min () -. Basierte Methode

Der Grund hierfür ist, dass die Abfrage eine geordnete Liste aller Gehälter pro Abteilung zu halten hat, wie es die Daten durchsucht, und der Rang wird dann später durch erneute Lesen dieser Liste zugeordnet werden. Offensichtlich in Abwesenheit von Indizes, die für diese genutzt werden können, können Sie nicht einen Rang zuweisen, bis der letzte Datenpunkt gelesen wurde, und die Wartung der Liste ist teuer.

So ist die Leistung des Rank () Funktion ist abhängig von der Gesamtzahl der Elemente gescannt wird, und wenn die Anzahl ausreichend ist, dass die Art auf der Festplatte schwappt dann wird die Leistung reduzieren.

Dies ist wahrscheinlich effizienter:

select dept,
       emp,
       salary
from
       (
       SELECT dept, 
              emp,
              salary,
              Min(salary) Over (Partition By dept) min_salary
       FROM   mytable
       )
where salary = min_salary
/

Diese Methode erfordert nur, dass die Abfrage einen einzelnen Wert pro Abteilung des Minimalwertes bisher begegnet halten. Wenn ein neues Minimum auftritt, ist dann der vorhandene Wert geändert wird, sonst wird der neue Wert verworfen. Die Gesamtzahl der Elemente, die im Speicher gehalten werden müssen ist auf die Anzahl der Abteilungen, nicht in der Anzahl der Zeilen abgetastet werden.

Es könnte sein, dass Oracle einen Codepfad zu erkennen hat, dass der Rang nicht wirklich in diesem Fall berechnet werden müssen, aber ich würde nicht auf sie wetten.

Der zweite Grund für die Abneigung gegen Rank () ist, dass es nur die falsche Frage beantwortet. Die Frage ist nicht „Welche Aufzeichnungen das Gehalt hat, die die erste Ranking ist, wenn die Gehälter pro Abteilung sind aufsteigend geordnet“, es ist „welche Datensätze das Gehalt hat, dass der Mindest pro Abteilung ist“. Das macht einen großen Unterschied für mich zumindest.

Andere Tipps

Ich glaube, Sie ziemlich nah mit Ihrer ursprünglichen Abfrage waren. Im Folgenden würde Ihre Testfall laufen und passen:

SELECT dept, 
  MIN(emp) KEEP(DENSE_RANK FIRST ORDER BY salary, ROWID) AS emp,
  MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary, ROWID) AS salary
FROM mytable
GROUP BY dept

Im Gegensatz zu den RANK () -Lösungen, diese Garantien höchstens eine Zeile pro Abteilung. Dass aber die Hinweise auf ein Problem: Was in einer Abteilung geschieht, wo es zwei Mitarbeiter auf dem niedrigsten Gehalt? Die RANK () -Lösungen werden beide Mitarbeiter zurückkehren - mehr als eine Zeile für die Abteilung. Diese Antwort wird man willkürlich wählen, und stellen Sie sicher, es gibt nur eine für die Abteilung.

Sie können die RANK() Syntax. Zum Beispiel wird diese Abfrage Ihnen sagen, wo ein Mitarbeiter Reihen innerhalb ihrer Abteilung in Bezug auf, wie groß ihr Gehalt ist:

SELECT
  dept,
  emp,
  salary,
  (RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES

Sie könnten dann Abfrage von diesem, wo salary_rank_within_dept = 1:

SELECT * FROM
  (
    SELECT
      dept,
      emp,
      salary,
      (RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
    FROM EMPLOYEES
  )
WHERE salary_rank_within_dept = 1
select e2.dept, e2.emp, e2.salary
from employee e2
where e2.salary = (select min(e1.salary) from employee e1)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top