E.S*_*raf 5 sql oracle oracle11g
我需要让我所在部门的员工薪水最低,而 我是通过反加入来做到这一点的。
select emp.employee_id,emp.last_name,emp.salary,emp.department_id
from employees emp
left join employees sml
on sml.department_id = emp.department_id and sml.salary < emp.salary
where sml.employee_id is null and emp.department_id is not null
Run Code Online (Sandbox Code Playgroud)
但有人告诉我,可以通过使用一次select的 window函数来做到这一点。但是我不能按department_id分组并同时使用它。那是虫子还是我愚蠢?
SELECT department_id,
min(salary) OVER (partition by department_id) as minsalary
FROM employees;
GROUP BY department_id
Run Code Online (Sandbox Code Playgroud)
SQL Developer说00979。00000-“不是GROUP BY表达式”
WITH cte AS (
SELECT
emp.*
,ROW_NUMBER() OVER (PARTITION BY emp.department_id ORDER BY emp.salary) as RowNumber
FROM
employees emp
)
SELECT c.*
FROM
cte c
WHERE
c.RowNumber = 1
Run Code Online (Sandbox Code Playgroud)
您可以使用ROW_NUMBER()上述方法按部门获取 1 行最低工资。如果您希望所有行都处于平局状态,请将其切换为RANK()
否则你可以这样做,MIN() OVER但这会给你带来联系
WITH cte AS (
SELECT
emp.*
,MIN(emp.salary) OVER (PARTITION BY emp.department_id) as DeptMinSalary
FROM
employees emp
)
SELECT c.*
FROM
cte c
WHERE
c.salary = c.DeptMinSalary
Run Code Online (Sandbox Code Playgroud)
作为派生表而不是公共表表达式:
SELECT t.*
FROM
(SELECT
emp.*
,ROW_NUMBER() OVER (PARTITION BY emp.department_id ORDER BY emp.salary) as RowNumber
FROM
employees emp) t
WHERE
t.RowNumber = 1
Run Code Online (Sandbox Code Playgroud)
关于这个主题的最后一个想法是因为你问“我可以在带有窗口函数的 SQL 查询中进行分组吗?” Alex 介绍说,它PARTITION BY就像窗口函数中的子分组。但使用GROUP BY窗口函数进行分组意味着GROUP BY将在评估窗口函数之前评估结果集。
如果您运行第二个查询而没有group by(您可能已经尝试过)(从您发布的多余分号开始),您将看到每位员工得到一行,每行显示其部门的最低工资。该最小值是分析值,min()因为它具有window子句。该PARTITION BY是等效的GROUP BY,但没有聚集在整个结果集。
获得相同结果的最简单方法(几乎)是使用RANK()分析函数,该函数根据分配的分区和顺序对值进行排序,同时考虑到联系:
SELECT employee_id, last_name, salary, department_id,
RANK() OVER (PARTITION BY department_id ORDER BY salary) AS rnk
FROM employees
ORDER BY department_id, rnk;
EMPLOYEE_ID LAST_NAME SALARY DEPARTMENT_ID RNK
----------- ------------------------- ---------- ------------- ----------
200 Whalen 4400 10 1
202 Fay 6000 20 1
201 Hartstein 13000 20 2
119 Colmenares 2500 30 1
118 Himuro 2600 30 2
117 Tobias 2800 30 3
116 Baida 2900 30 4
115 Khoo 3100 30 5
114 Raphaely 11000 30 6
...
102 De Haan 17000 90 1
101 Kochhar 17000 90 1
100 King 24000 90 3
...
Run Code Online (Sandbox Code Playgroud)
对于部门20和30,您可以看到排名最低的行是最低工资。对于部门90,有两名排名第一的员工,因为他们的最低工资相同。
您可以将其用作内联视图,并仅选择排名第一的行:
SELECT employee_id, last_name, salary, department_id
FROM (
SELECT employee_id, last_name, salary, department_id,
RANK() OVER (PARTITION BY department_id ORDER BY salary) AS rnk
FROM employees
)
WHERE rnk = 1
ORDER BY department_id;
EMPLOYEE_ID LAST_NAME SALARY DEPARTMENT_ID
----------- ------------------------- ---------- -------------
200 Whalen 4400 10
202 Fay 6000 20
119 Colmenares 2500 30
203 Mavris 6500 40
132 Olson 2100 50
107 Lorentz 4200 60
204 Baer 10000 70
173 Kumar 6100 80
101 Kochhar 17000 90
102 De Haan 17000 90
113 Popp 6900 100
206 Gietz 8300 110
178 Grant 7000
13 rows selected.
Run Code Online (Sandbox Code Playgroud)
如果您不必担心联系,那么还有一个更简单的选择,但这在这里不合适。
请注意,这比原始查询多了一行。您正在加入on sml.department_id = emp.department_id。如果部门ID为null(与员工178相同),则该联接失败,因为您无法使用相等性测试将null与null进行比较。因为此解决方案没有联接,所以该联接不适用,并且您会在结果中看到该员工。
首先要记住的是,窗口函数(如OVER()子句)对查询结果起作用。即:服务器首先执行查询,然后才应用您定义的窗口函数。
这意味着你实际上可以在同一个查询中使用窗口函数和 group by 子句,但你需要封装它,像这样:
SELECT department_id,
min(min(salary)) OVER (partition by department_id) as minsalary
FROM employees
GROUP BY department_id;
Run Code Online (Sandbox Code Playgroud)
但是,我同意这不是使用窗口函数的好地方。马特的提议在这里是最好的(ROW_NUMBER()在CTEor 中subquery,然后只在 main 中选择所需的行SELECT)。
| 归档时间: |
|
| 查看次数: |
8151 次 |
| 最近记录: |