【问题标题】:Is my JOIN + GROUP BY ... HAVING COUNT query correct?我的 JOIN + GROUP BY ... HAVING COUNT 查询是否正确?
【发布时间】:2012-06-08 23:23:52
【问题描述】:

我是 SQL 新手,我想实现以下查询:

我有两张桌子,LicenseTblUnlockTbl

LicenseTbl 包含有关购买的软件许可证的信息:

LicenseID、ProgramID、Owner、Location、OrderNo、BlockTime

UnlockTbl 包含有关特定软件注册的信息:

UnlockID、LicenseID(LicenseTbl 中的外键)、时间戳、序列号、密钥、卸载时间

如果许可证被阻止或软件已卸载,则 BlockTime 和 UninstallTime 包含时间戳,否则包含 NULL

我想设计一个查询,为我提供满足以下条件的所有 LicenseID:

  • 属于给定客户,
  • 未被阻止,
  • 要么未列在 UnlockTbl 中,要么行中有

我已经写了这个,但我不确定它是否绝对正确(这是我第一次使用 SQL 查询):

SELECT LicenseID FROM LicenseTbl
JOIN UnlockTbl
   ON (LicenseTbl.LicenseID = UnlockTbl.LicenseID) 
WHERE  LicenseTbl.OrderNo   = '$givenOrderNo'
   AND LicenseTbl.Owner     = '$givenOwner'
   AND LicenseTbl.Location  = '$givenLocation'
   AND LicenseTbl.BlockTime IS NULL
   AND UnlockTbl.UninstallTime IS NULL
GROUP BY LicenseTbl.LicenseID, UnlockTbl.Key
HAVING COUNT(*) < $X

(这应该意味着,列出所有同时使用少于 X 次的许可证。我更喜欢那些首先使用最少但不知道如何排序的许可证。)

【问题讨论】:

  • 那么,当你运行它时会发生什么?是否正确的测试将是您是否获得所需的数据。你不能用SELECT 破坏服务器上的任何数据,所以试试吧......
  • 是的,这就是我正在做的事情,它似乎适用于我的测试数据,但我不知道如何按计数排序。真正的数据库有成千上万的条目,所以我无法确定是否缺少任何内容。
  • 那么我要做的是在您的测试数据中创建 8 条记录:1 条应该返回,3 条打破每个排除条件,3 条打破每个组合中的 2 个排除条件,和 1 打破所有 3. 运行您的查询,并确保您只取回一条记录。如果这行得通,可以放心地假设它会扩大规模。
  • 我同意戴夫的观点。 SQL 查询通常需要两种类型的测试;逻辑和性能。性能测试需要大量(现实) 数据集。但逻辑测试只需要 描述所有 存在的极端情况的数据。它可以是小型的、可制造的并且易于验证。 但是,您可能忘记了需要测试的角落案例;识别所有案例需要非常严格的方法。在这种情况下,从真实数据中获取随机案例并通过手动其他一些自动化逻辑来验证它们也是很好的。

标签: php mysql sql count group-by


【解决方案1】:

这是一个好的开始,但我会将查询更改为以下内容...

SELECT
  LicenseID
FROM
  LicenseTbl
LEFT JOIN
  UnlockTbl
    ON  UnlockTbl.LicenseID = LicenseTbl.LicenseID
    AND UnlockTbl.UninstallTime IS NULL
WHERE
      LicenseTbl.OrderNo   = '$givenOrderNo'
  AND LicenseTbl.Owner     = '$givenOwner'
  AND LicenseTbl.Location  = '$givenLocation'
  AND LicenseTbl.BlockTime IS NULL
GROUP BY
  LicenseTbl.LicenseID
HAVING
  COUNT(DISTINCT UnlockTbl.SerialNo) < $X
ORDER BY
  COUNT(DISTINCT UnlockTbl.SerialNo)

1)。 LEFT JOIN

LEFT JOIN 确保返回 LicenseTbl 中的所有行,即使 UnlockTbl 表中没有匹配项。 (如果没有匹配,UnlockTbl 表的值都表示为NULL。)

2)。 UnlockTbl.UninstallTime IS NULLJOIN 而不是 WHERE

WHERE 子句在JOIN 之后应用。这意味着UnlockTbl 中的任何记录,其中UninstallTime 具有实际值(NOT NULL) 被加入,然后 被过滤掉。这反过来意味着,如果 所有 UnlockTbl 中的相关记录在 UninstallTime 中具有非 NULL 值,则该许可证的所有行都将被过滤。

3)。 GROUP BY 只是许可证,而不是密钥。

简单地说,我不知道你为什么把它放在那里,而且它没有出现在你想要的英文描述中。

如果您需要 LicenseID 列表,按该字段分组可确保每个 LicenseID 获得一条记录。

4)。 HAVING 子句修改为查看COUNT(DISTINCT SerialNo)

COUNT(*) 计算所有记录。即使没有匹配(所有UnlockTbl 值都显示为NULL),这也会返回1

COUNT(SerialNo) 只计算SerialNo 不为空的记录。如果没有匹配(所有UnlockTbl 值显示为NULL),这将返回0

COUNT(DISTINCT SerialNo) 也只计算 SerialNo 不为 NULL 的记录,但将 sme 值的重复项视为仅 1 个条目。

5)。 ORDER BY COUNT(DISTINCT SerialNo)

采用与HAVING 子句中过滤相同的值,并按其排序。

【讨论】:

  • 有据可查,以阐明不同的元素以及它们如何联系在一起。
  • 哇,谢谢,这真的很有帮助! (对于(3),我可能有错误的印象,即序列号上的GROUP BY 会以某种方式影响我的计数。而KeySerialNo 的错字/“thinko”。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-23
  • 2016-10-11
  • 2010-10-30
  • 2014-01-30
  • 1970-01-01
  • 2021-04-25
相关资源
最近更新 更多