我需要员工薪水最低的员工 我是用反连接做的。
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
但是我被告知可以使用窗口功能使用一个选择来实现。 但是我无法通过department_id对其进行分组并同时使用它。 这是一个错误还是我是愚蠢的?
SELECT department_id,
min(salary) OVER (partition by department_id) as minsalary
FROM employees;
GROUP BY department_id
SQL Developer说00979. 00000 - &#34;不是GROUP BY表达式&#34;
答案 0 :(得分:4)
如果您在没有group by
的情况下运行第二个查询 - 您可能已经尝试过,从您发布的内容中添加分号 - 您将看到每个员工都获得一行,每个都显示他们部门的最低工资。最小值是分析min()
,因为它有一个窗口子句。 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
...
对于部门20和30,您可以看到排名为1的行是最低薪水。对于90部门,有两名员工排名第一,因为他们的薪水最低。
您可以将其用作内联视图,并仅选择排名为1的行:
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.
如果你不必担心关系,那就有一个更简单的选择,但这里不合适。
请注意,这比您的原始查询多一行。您正在加入on sml.department_id = emp.department_id
。如果部门ID为空,就像员工178那样,则该连接失败,因为您无法通过相等性测试将null与null进行比较。由于此解决方案没有加入,因此不适用,并且您在结果中看到该员工。
答案 1 :(得分:2)
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
您可以使用ROW_NUMBER()
按部门获得一行最低薪水。如果您希望绑定情况下的所有行都将其切换为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
作为派生表而不是公用表表达式:
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
关于这个主题的最后一个想法是因为你问“我可以在带有窗口函数的SQL查询中进行分组吗?” Alex说明PARTITION BY
就像是Window Function中的子分组。但是使用带有Window函数的GROUP BY
分组意味着将在正在评估的Window函数之前评估GROUP BY
结果集。
答案 2 :(得分:2)
要记住的第一件事是窗口函数(如OVER()
子句)对查询结果起作用。即:服务器首先执行查询,然后才应用您定义的窗口函数。
这意味着您实际上可以在同一查询中使用窗口函数和group by子句,但需要对其进行封装,如下所示:
SELECT department_id,
min(min(salary)) OVER (partition by department_id) as minsalary
FROM employees;
GROUP BY department_id
但是,我同意这不是使用窗口函数的好地方。 Matt的主张最好在这里(ROW_NUMBER()
或CTE
中的subquery
,然后仅在主SELECT
中选择所需的行)。
答案 3 :(得分:0)
在这种情况下你不需要窗口函数,因为简单的group by
也会起作用。
错误是正确的,因为窗口函数不是聚合函数。 窗口函数不能成为Group by-member。
但你可以使用&#34; distinct&#34;代替。
SELECT DISTINCT department_id,
min(salary) OVER (partition by department_id) as minsalary
FROM employees;
在你的特殊情况下,当然这一切都是超大的。但我认为理解是游戏的名称。