【问题标题】:Extra constraints on columns not appeared in GROUP BY without JOIN没有 JOIN 的 GROUP BY 中没有出现的列的额外约束
【发布时间】:2019-06-17 20:22:22
【问题描述】:

考虑下表:

Company     BuildYear   ProductName   Cost
------    -----------   -----------   ----
  Foo         1900          A_1        50
  Foo         2000          B_1        50
  Foo         2000          B_2        50

  Bar         1900          A_1        50
  Bar         1900          A_2        100
  Bar         2000          B_1        50

查询 #1(简单):

我们正在寻找在 1900 年只生产一种产品的公司。在上面的示例中,只有Foo 公司拥有 A_1 产品(Bar 公司生产两种不同类型的产品,即 A_1 和 A_2)

为此,查询将是:

SELECT *
FROM Table
WHERE BuildYear=1900
GROUP BY ProductName
HAVING COUNT(*) = 1

查询 #2(我的问题):

现在我们正在寻找在 1900 年只生产一种产品,并且这种产品的成本低于 75 美元的公司。对于上面的示例表,答案还是只有Foo 公司。

不用说,只需将AND cost<75 添加到上述查询中就会返回错误的答案(FooBar)。将其添加到 HAVING 子句也会引发以下错误消息:

“成本”列必须出现在 GROUP BY 子句中或用于聚合函数中

另一方面,我不希望将上述查询的结果再次与原始表连接(如果可能),因为该表实际上很大。

任何反馈都将不胜感激。

更新: 上面显示的列仅用于演示,在实际表中它们都是 TEXT(因此 MIN/MAX 技巧不适用)

更新:为什么将AND cost<75 添加到WHERE 子句不起作用?因为该子句切断了Bar::A_2 产品,并且在之后HAVING 进行评估时,它认为Bar 是一家只有一种产品的公司。

【问题讨论】:

  • 不确定我是否了解所有内容,但您不应该简单地在 where 子句中包含 and cost < 75 吗?顺便说一句,在我看来,Foo 在 1900 年确实有两行。
  • 我修正了后一点。我会详细说明为什么一个简单的并且不能在一分钟内工作。

标签: sql postgresql performance


【解决方案1】:

如果只有一个产品,那么您可以使用MIN()MAX() -- 如果组中只有一行,则它们具有相同的值:

SELECT *
FROM Table
WHERE BuildYear = 1900
GROUP BY ProductName
HAVING COUNT(*) = 1 AND MIN(COST) < 75;

如果您将数字存储为文本,则应修复数据。

除此之外,只需转换它:

HAVING COUNT(*) = 1 AND MIN(COST::NUMERIC) < 75;

【讨论】:

  • 不适用于我的问题。我为我的问题添加了更新。请阅读。
  • @Emadpres 。 . .当然,MIN()MAX() 适用于文本类型。我不知道您的问题是什么,除非您将数字存储为文本。
  • 哦,酷!我不知道!是 hack,还是可以将它们与文本一起使用?
  • 它可以工作,但您需要将其转换为一个数字(如 Gordon 的第二个示例)。否则将无法正常工作。作为文本,100000000 将“小于”2。
  • @Emadpres 。 . .对于相等,您可以使用=,但您可能有尾随空格或隐藏字符会造成问题。对于数字比较,您需要将值转换为数字(如现在的答案所示)。真正的解决方案是修复您的数据,以便以正确的类型存储数字。我只是感到困惑,因为代码 cost &lt; 75 直接来自您的问题。在那里使用它看起来很舒服。
猜你喜欢
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 2021-04-01
  • 1970-01-01
  • 2021-01-09
  • 2010-10-17
  • 2011-09-01
相关资源
最近更新 更多