我有以下数据库表
Firstname Varchar(40)
Surname Varchar(40)
Department Binary
JobCode Char(1)
Run Code Online (Sandbox Code Playgroud)
通常情况下,提取特定部门的记录是没有问题的。部门字段是一个由 7 部分组成的字段,每一位代表一个特定的部门,允许系统轻松显示人们在一个或多个部门工作的位置。假设 John Smith 的工作代码为 K,而 Freda Williams 的工作代码为 M。
同样,返回特定部门的记录非常简单。但是,如果 John Smith 临时晋升到同一部门,而不是更改记录,则会添加一个带有职位代码 F的额外记录。本质上,职位代码字母越低,等级越高。
因此,如果我们要检索 John Smith 的当前详细信息,很简单,选择姓名为 John Smith 的记录,按 Job Code Asc, Limit (1) 排序。
但是,提取一个部门的所有记录的 SQL 语句是什么,但要确保John Smith只出现一个记录,而且它是“F”记录?任何人都可以帮忙吗?我原以为子查询可能会对它进行排序,但不知道如何排序。
请允许我首先回顾一下直接导致您遇到此问题的表设计决策(或之前的那些决策),以及如何避免它。如果您不想阅读它,请直接转到最后,我建议在此处编辑实际解决方案。
您有一个表,里面塞满了多个设计实体。虽然这本身并不坏,但您必须意识到您正在对表设计进行非规范化,这可能会导致问题。
我在同一张桌子上看到 3 个概念:
根据您的描述,一名员工可以是多个部门的一部分(反之亦然),您正在将其作为位字段来实现。我发现有趣的是您选择了一种binary数据类型,而 a bit或 aset数据类型分别可能更小且更清晰。但是,通常避免使用这些数据类型,不仅因为它们不是很标准,还因为它们用于对列进行非规范化。
假设有一个departments表,更好的选择是创建一个单独的表:DepartmentEmployees,像这样
Employees Table
===============
EmployeeId Int Primary Key auto_increment
Firstname Varchar(40)
Surname Varchar(40)
JobCode Char(1)
DepartmentEmployees
===================
EmployeeId Int
DepartmentId Int
Primary Key(EmployeeID, DepartmentId)
Run Code Online (Sandbox Code Playgroud)
要查询给定部门的所有员工“?”:
SELECT E.*
FROM Employees E
JOIN DepartmentEmployees DE
ON E.Id = DE.EmployeeID
WHERE DepartmentId = ?
Run Code Online (Sandbox Code Playgroud)
现在让我们来看看 JobCode。您必须问问自己,工作职位是员工的财产还是部门内员工的财产。如果是后者,请考虑在那里添加该属性:
Employees Table
===============
EmployeeId Int Primary Key auto_increment
Firstname Varchar(40)
Surname Varchar(40)
DepartmentEmployees
===================
EmployeeId Int
DepartmentId Int
JobCode Char(1)
Primary Key(EmployeeID, DepartmentId)
Run Code Online (Sandbox Code Playgroud)
要查询给定部门“?”中的所有员工及其工作代码:
SELECT E.*, DE.JobCode
FROM Employees E
JOIN DepartmentEmployees DE
ON E.Id = DE.EmployeeID
WHERE DepartmentId = ?
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以获得 JobCode,对于每个员工部门元组(如果需要),它可以不同。
您可以考虑为部门、职位(如职位、职位代码)创建(如果它们不存在)、单独的表,并在各处添加唯一的主键。
一般来说,只要有 N:N 关系就创建一个中间表是一个不错的选择,除非有理由对关系进行非规范化(导致更复杂的代码)。
编辑:从各方面来看,您面临的问题都是可怕的 - 除了规范化问题之外,添加一个额外的记录是没有意义的。但这是想要的解决方案:
知道你对此无能为力,你很幸运,因为它是一个非常常见的查询 - 不仅有一个名称“GROUPWISE MAXIMUM”,它甚至在 MySQL 手册上有自己的页面:http://dev.mysql .com/doc/refman/5.7/en/example-maximum-column-group-row.html
有一个子查询和一个 JOIN 解决方案,我通常更喜欢 JOIN 解决方案,它会是这样的:
SELECT E1.FirstName, E1.Surname, E1.Department, s1.JobCode
FROM Employees E1
LEFT JOIN Employees E2
ON E1.FirstName = E2.FirstName AND E1.Surname = E2.Surname -- use an id for the SELF JOIN if possible, whatever is unique
AND E1.JobCode < E2.JobCode -- change the direction of the comparison depending if you want the lowest or the highest JobCode
WHERE E2.FirstName IS NULL -- again, use the id if available
AND E1.Department = ...; -- or whatever the department filter should look like in your current setup
Run Code Online (Sandbox Code Playgroud)
写完这样的解决方案后,请允许我淋浴。