因此,我不得不说,到目前为止,SQL是我作为开发人员的最薄弱的一面。也许我要完成的工作很简单。我有一个类似的东西(它不是真正的模型,但是为了使它易于理解而又不浪费太多时间来解释它,我想出一个例子来模仿我必须使用的表关系)。一方面,我们将其称为“用户”。诸如主键“ UserId”,“ UserName”之类的列。
接下来,另一个表“许可证”。与用户1:N相关,每个许可证属于一个用户,一个用户可能有多个许可证。因此,我们将拥有一个PK IdLicense,一个FK IdUser,等等。
接下来,一个名为“设备”的表。在这里,我们定义了不同的设备。IdEquipment,设备名称。没有更多的话要说了。
最后,创建在“许可证”和“设备”之间建立N:M关系的表。当用户定义许可证时,他们可以指定许可证允许他们操作的不同设备。因此,一个许可证可以涉及多个设备,而一个设备可以涉及多个许可证。
真正的交易来了。我已下令实施某种搜索系统,该系统可让您根据他们有资格使用的设备来吸引用户。可以进行多项选择,以便您搜索有资格处理设备的用户“ A ”,“ B”和“ C”。例如,我们有2个用户,James和Dave。詹姆斯有2个许可证,戴夫(Dave)有1个。詹姆斯有资格在第一个许可证上使用机器“ A”和“ D”,在第二个许可证上使用“ B”和“ C”。戴夫有资格在其唯一的许可证上处理“ B”和“ C”类型的设备。如果有人试图搜索能够处理设备“ A”,“ B”和“ C”的用户,则只有James是返回记录。
到目前为止,我认为我必须做类似的事情
SELECT DISTINCT IdUser FROM Users INNER JOIN Licenses ON Licenses.IdUser = Users.idUser INNER JOIN LicensesEquipments ON LicensesEquipments.IdLicense = Licenses.IdLicense INNER JOIN Equipment ON Equipment.IdEquipment = LicensesEquipments.IdEquipment WHERE Equipment.IdEquipment = ??
如何在“ A”,“ B”和“ C”的所有3种不同的idEquipments上对此进行过滤?显然,我不能使WHERE Equipment.IdEquipment = 1和Equipment.IdEquipment = 2,因为单元格不能等于2个不同的值。我无法执行WHERE Equipment.IdEquipment = 1或Equipment.IdEquipment = 2,因为使用OR意味着持有至少一种可能性的任何用户都将被视为有效结果,并且我正在寻找具有所有3种可能的结果在这种情况下的不同设备。
最初,我假设我必须使用别名创建表设备的多个内部联接,并使用我可能在设备上具有的过滤器的次数进行多次,并且将每个别名与不同的过滤器一起使用。但是后来我的代码主管走了,告诉我忘了它,因为他说添加更多的过滤器会增加成本(尽管他没有给我更好的选择…)
SELECT Users.idUser FROM Users INNER JOIN Licenses ON Licenses.IdUser = Users.idUser INNER JOIN LicensesEquipments ON LicensesEquipments.IdLicense = Licenses.IdLicense INNER JOIN Equipment ON Equipment.IdEquipment = LicensesEquipments.IdEquipment WHERE Equipment.IdEquipment IN ('A', 'B', 'C') GROUP BY IdUser HAVING COUNT(DISTINCT Equipment.IdEquipment) = 3 <--must be # of unique items in IN clause
如果您确实只需要用户ID,则可以从查询中删除Users和Licenses表:
Users
Licenses
SELECT Licenses.IdUser FROM Licenses INNER JOIN LicensesEquipments ON LicensesEquipments.IdLicense = Licenses.IdLicense WHERE LicensesEquipments.IdEquipment in ('A', 'B', 'C') GROUP BY Licenses.IdUser HAVING COUNT(DISTINCT LicensesEquipments.IdEquipment) = 3
另外,一些别名使阅读起来更容易:
SELECT l.IdUser FROM Licenses l INNER JOIN LicensesEquipments le ON le.IdLicense = l.IdLicense WHERE le.IdEquipment in ('A', 'B', 'C') GROUP BY l.IdUser HAVING COUNT(DISTINCT le.IdEquipment) = 3