带有 SQL MIN() 和 GROUP BY 的额外字段
Posted
技术标签:
【中文标题】带有 SQL MIN() 和 GROUP BY 的额外字段【英文标题】:Extra Fields with SQL MIN() & GROUP BY 【发布时间】:2010-10-17 21:46:23 【问题描述】:当使用 SQL MIN() 函数以及 GROUP BY 时,任何其他列(不是 MIN 列或 GROUP BY 列之一)是否会与匹配的 MIN 行中的数据匹配?
例如,给定一个包含部门名称、员工名称和薪水的表:
SELECT MIN(e.salary), e.* FROM employee e GROUP BY department
显然我会得到两个不错的列,最低工资和部门。员工姓名(和任何其他员工字段)是否来自同一行?即具有 MIN(salary) 的行?
我知道很可能有两个员工的薪水相同(并且最低),但我(现在)关心的只是获取有关(或一个)的所有信息最便宜的员工。
这会选择最便宜的推销员吗?
SELECT min(salary), e.* FROM employee e WHERE department = 'sales'
基本上,我能否确定与 MIN() 函数一起返回的数据将与具有该最小值的(或单个)记录相匹配?
如果数据库很重要,我正在使用 mysql。
【问题讨论】:
【参考方案1】:另一种方法是使用分析函数。这是使用分析和 ROW_NUM 函数的查询
select first_name,salary from (select first_name,salary, Row_NUMBER() over (PARTITION BY DEPARTMENT_ID ORDER BY Salary ASC) as row_count from employees) where row_count=1;
【讨论】:
【参考方案2】:最快的解决方案:
SET @dep := '';
SELECT * FROM (
SELECT * FROM `employee` ORDER BY `department`, `salary`
) AS t WHERE IF ( @dep = t.`department`, FALSE, ( @dep := t.`department` ) OR TRUE );
【讨论】:
【参考方案3】:SELECT e.*
FROM employee e
WHERE e.id =
(
SELECT id
FROM employee ei
WHERE ei.department = 'sales'
ORDER BY
e.salary
LIMIT 1
)
要获取每个部门的值,请使用:
SELECT e.*
FROM department d
LEFT JOIN
employee e
ON e.id =
(
SELECT id
FROM employee ei
WHERE ei.department = d.id
ORDER BY
e.salary
LIMIT 1
)
要仅为那些有员工的部门获取值,请使用:
SELECT e.*
FROM (
SELECT DISTINCT eo.department
FROM employee eo
) d
JOIN
employee e
ON e.id =
(
SELECT id
FROM employee ei
WHERE ei.department = d.department
ORDER BY
e.salary
LIMIT 1
)
当然,在(department, salary)
上建立索引将大大改善所有三个查询。
【讨论】:
请注意,OP 还希望查询中包含最小值。这个解决方案很接近,但不是 100% 的要求。 查询选择所有值,包括薪水。 适用于销售最低的员工,那么第一个示例查询,每个部门的最低员工呢?当然,我可以为每个部门运行您的查询,但是任何可以在单个查询中工作的东西? 好点。我没有想到那一排的工资会和最低工资一样。对此感到抱歉。【参考方案4】:如果您想在每个部门中获得“最便宜”的员工,您将有两个选择:
SELECT
E.* -- Don't actually use *, list out all of your columns
FROM
Employees E
INNER JOIN
(
SELECT
department,
MIN(salary) AS min_salary
FROM
Employees
GROUP BY
department
) AS SQ ON
SQ.department = E.department AND
SQ.min_salary = E.salary
或者你可以使用:
SELECT
E.*
FROM
Employees E1
LEFT OUTER JOIN Employees E2 ON
E2.department = E1.department AND
E2.salary < E1.salary
WHERE
E2.employee_id IS NULL -- You can use any NOT NULL column here
第二个语句的工作原理是,告诉我所有员工,你在同一部门找不到其他工资较低的员工。
在这两种情况下,如果两名或多名员工的最低工资相同,您将获得他们(全部)。
【讨论】:
MySQL 有分析功能吗?如果是这样,无论何时您将表连接回自身,您都应该立即想到“使用分析函数更快”以上是关于带有 SQL MIN() 和 GROUP BY 的额外字段的主要内容,如果未能解决你的问题,请参考以下文章
带有 MIN 和 MAX 的 GROUP BY - 属于解决方案的日期范围
SQL - 多 SELECT 和 GROUP BY 以获取表的 MIN(value)
使用 MIN() 和 GROUP BY [重复] 时,SQL SELECT 的行为不符合预期
SQL 10位时间戳 除以60 得到整分钟;group by event_ts/60<==> group by 1min
SQL 10位时间戳 除以60 得到整分钟;group by event_ts/60<==> group by 1min