SQL查询:如何将整数更改为布尔值

时间:2018-07-24 09:58:54

标签: sql delphi firebird

我正在使用Firebird 2.5.8和Delphi 10.2.3,并且想用查询填充DBGrid:

SELECT c.ID, l.ID,
(
SELECT COUNT(pl.ID)
FROM Tbl_ProtocolLicense AS pl
WHERE (pl.ReferenceId=l.ID)
) AS ReferenceCount

FROM  Tbl_License AS l, tbl_client AS c
WHERE l.ClientId=c.Id;

如何为该查询添加一个值(ReferenceCount> 0)作为布尔值或(0/1)?

1 个答案:

答案 0 :(得分:2)

为什么还要使用一个关联查询,该查询将为每一行一次又一次地重新计算?

第一个查询实际上不起作用。太草率了。

SELECT 
  c.ID,
  l.ID, 
  IIF( r.CNT > 0, 1, 0 )
FROM Tbl_License AS l
  JOIN tbl_client AS c ON l.ClientId=c.Id
  JOIN (
    SELECT COUNT(*) as CNT, ReferenceId as ID
    FROM Tbl_ProtocolLicense 
    GROUP BY 2
        ) as r ON r.ID = l.ID

注意:这假设Tbl_ProtocolLicense.ID列永远不会是NULL


UPD。我在http://stackoverflow.com/a/51159126/976391上做了一些关于COUNT和其他聚合的演讲-但我自己错过了。

 SELECT COUNT(*) as CNT, ReferenceId as ID
        FROM Tbl_ProtocolLicense 
        GROUP BY 2

运行查询并查看结果。注意到有什么腥吗?

此查询仅返回确实存在的行,而不返回不存在的行。

中间分组查询将没有一行,其中count = 0! 因此整个基于内部联接的查询也不会包含它们!

我们应该使用外部联接,即使在另一个表中没有匹配的行,也可以让行存在。阅读:https://en.wikipedia.org/wiki/Join_(SQL)

SELECT 
  c.ID,
  l.ID, 
  IIF( r.CNT is not NULL, 1, 0 )
FROM Tbl_License AS l
  JOIN tbl_client AS c ON l.ClientId=c.Id
  LEFT JOIN (
    SELECT COUNT(*) as CNT, ReferenceId as ID
    FROM Tbl_ProtocolLicense 
    GROUP BY 2
        ) as r ON r.ID = l.ID

将输出与第一个查询进行比较,看看差异。


UPD2。但是,即使那样还不够好。这里的问题是“你说你想要你实际上不想要的东西”。

当您真的不关心计数时,您要求Firebird计数所有行。您所关心的只是“是否至少有一行或根本没有”。如果有一行-您不在乎是否还有10或100或1000。因此,当您不希望对对象进行计数时,实际上对它们进行计数是一项额外的工作,无所作为。

这在Interbase / Firebird系列中特别浪费,因为对表进行计数会触发garbage collection并减慢工作速度。但是,即使在纯Delphi中也是如此-如果您对找到数组的第一个适合元素感到满意,就不想遍历所有数组。

然后我们可以返回到相关的子查询。

SELECT 
  c.ID,
  l.ID,
  IIF( EXISTS ( 
         SELECT * FROM Tbl_ProtocolLicense AS pl
         WHERE pl.ReferenceId=l.ID 
       ), 1, 0 )   
FROM  Tbl_License AS l, tbl_client AS c
WHERE l.ClientId=c.Id;
  • q.s.q。的苦涩一面是它针对每个结果行一次又一次地运行
  • 计算分组总数的痛苦一面-实际上,您不需要该数据,也不需要确切的计数。

哪个更糟?谁知道。根据实际数据和实际表/索引,可能会出现一种或另一种方法会更快的情况。人类不会注意到小数据上的差异。这是关于“扩展”成千上万个真实数据的问题,差异将在哪里显示。


UPD 3.我们可以同时使用两种方法中的最佳方法吗?我希望可以。诀窍是-准确地问我们需要什么,什么都不要。我们可以要求Firebird列出表中所有的ID而不实际计算它们吗?是的,有。

 SELECT DISTINCT ReferenceId FROM Tbl_ProtocolLicense  

运行查询并查看结果!

注意,它仍然不会列出不在表中的ID。明显?好吧,我在第一种方法中错过了它,然后两个支持我的人也错过了。愚蠢的错误最难以发现,因为您无法相信这样的愚蠢。

因此,现在我们必须将其插入,而不是第二次尝试的“计数”查询。

SELECT 
  c.ID,
  l.ID, 
  IIF( r.ReferenceId is NULL, 0, 1 )
FROM Tbl_License AS l
  JOIN tbl_client AS c ON l.ClientId=c.Id
  LEFT JOIN (
    SELECT DISTINCT ReferenceId 
    FROM Tbl_ProtocolLicense 
      ) as r ON r.ReferenceId = l.ID

UPD。 4最后一招。如果我是正确的,则此查询将具有与上面完全相同的结果,而无需使用IIF / CASE。试试看并比较。如果结果相同,则尝试了解其原因,工作方式以及所需的数据假设。

SELECT 
  c.ID,
  l.ID, 
  COUNT( r.ReferenceId )
FROM Tbl_License AS l
  JOIN tbl_client AS c ON l.ClientId=c.Id
  LEFT JOIN (
    SELECT DISTINCT ReferenceId 
    FROM Tbl_ProtocolLicense 
      ) as r ON r.ReferenceId = l.ID
GROUP BY c.ID, l.ID

此查询并不比Upd.3更好,它只是一个思考,然后更好地理解SQL的任务。


现在做一些工作来实际检查和比较结果,因为盲目地信任Internet上的未知人员并不好。即使该人不是恶意的,他也可能犯愚蠢的错误。

无论您从Internet论坛中浏览什么,都只是“示例”和“想法演示”,理解和检查该示例始终是您的责任。也许拒绝它。


阅读和理解:

另外,对您而言,阅读一些关于常规SQL的好书对您真的很有用,例如Martin Gruber的书

相关问题