小编典典

选择“按单个列的多个值过滤内部联接查询时不同”?

sql

因此,我不得不说,到目前为止,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种可能的结果在这种情况下的不同设备。

最初,我假设我必须使用别名创建表设备的多个内部联接,并使用我可能在设备上具有的过滤器的次数进行多次,并且将每个别名与不同的过滤器一起使用。但是后来我的代码主管走了,告诉我忘了它,因为他说添加更多的过滤器会增加成本(尽管他没有给我更好的选择…)


阅读 148

收藏
2021-05-23

共1个答案

小编典典

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,则可以从查询中删除UsersLicenses表:

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
2021-05-23