【问题标题】:Sybase: HAVING operates on rows?Sybase:HAVING 对行进行操作?
【发布时间】:2013-03-19 18:38:37
【问题描述】:

我遇到过以下 SYBASE SQL:

-- Setup first
create table #t (id int, ts int)
go

insert into #t values (1, 2)
insert into #t values (1, 10)
insert into #t values (1, 20)
insert into #t values (1, 30)

insert into #t values (2, 5)
insert into #t values (2, 13) 
insert into #t values (2, 25)
go

declare @time int select @time=11
-- This is the SQL I am asking about
select * from (select * from #t where ts <= @time) t group by id having ts = max(ts)
go

这条SQL的结果是

 id          ts          
 ----------- ----------- 
           1          10 
           2           5 

这看起来像 HAVING 条件应用于行而不是组。有人可以指点我一个地方是描述这种情况的 Sybase 15.5 文档吗?我所看到的只是“HAVING 对组进行操作”。我在文档中看到的最接近的是:

having 子句可以包含不在其中的列或表达式 选择列表而不是 group by 子句。

(引用自here)。

但是,他们并没有准确解释当你这样做时会发生什么。

【问题讨论】:

  • 您确定这是 Sybase 吗?我认为 Sybase 在group by id 上会失败,因为tsselect 列表中但不在聚合中。这看起来更像 MySQL。
  • 是的,这是 Sybase 15。Sybase 支持这一点 - 请参阅我提供的 Sybase 手册中的引文以结束问题。
  • 这是一个较新的 Sybase 功能。在 MySQL 中,这将返回一行中的任意值。它不会做你所期望的。我很失望另一个数据库决定包含这个错误功能。
  • @Arkadiy,即使 sybase 支持它,使用此功能也是一个糟糕的主意,因为您不会总是得到您期望的结果,正如 mysql 人所发现的那样。未能完全指定 group by 子句是 SQL 反模式。不仅会出现问题,你会得到你想要的结果,而且更难维护。但我真的不确定你会期待什么其他结果。也许如果您告诉我们,我们可以为您指出将获得它的代码。
  • @HLGEM 我不期待另一个结果 - 我希望有人能指出我在 Sybase 文档中的一个地方,以保证这个结果不是偶然的。正如你所说,我可能不会得到我所期望的——除非 Sybase 在某处正式描述了这一点。

标签: sql sap-ase


【解决方案1】:

我的理解:是的,从根本上说,HAVING 对行进行操作。通过省略 GROUP BY,它对单个“超组”内的所有结果行进行操作,而不是对组内的行进行操作。阅读您最初链接的 Sybase 文档中的“分组方式和使用聚合查询如何工作”部分:-

分组和查询聚合的工作原理

  • where 子句排除不符合其搜索条件的行;对于分组查询或非分组查询,其功能保持不变。
  • group by 子句针对 group by 表达式中的每个唯一值将剩余的行收集到一个组中。省略 group by 会为整个表格创建一个组。
  • 选择列表中指定的聚合函数计算每个组的汇总值。对于标量聚合,表只有一个值。向量聚合计算不同组的值。
  • having 子句从不满足其搜索条件的结果中排除组。即使 having 子句只测试行,group by 子句的存在或不存在可能使它看起来像是对组进行操作:
    • 当查询包含 group by 时,have 会排除结果组行。这就是为什么拥有似乎对群体起作用。
    • 当查询没有group by 时,have 会从(单组)表中排除结果行。这就是为什么 have 似乎对行进行操作(结果类似于 where 子句的结果)。

其次,在"How the having, group by, and where clauses interact"部分出现一个简短的总结:-

have、group by 和 where 子句如何交互

当您在查询中包含 havinggroup bywhere 子句时,每个子句影响行的顺序决定了最终结果:

  • where 子句排除不符合其搜索条件的行。
  • group by 子句针对 group by 表达式中的每个唯一值将剩余的行收集到一个组中。
  • 选择列表中指定的聚合函数计算每个组的汇总值。
  • having 子句从最终结果中排除不符合其搜索条件的行。

@SQLGuru 的解释就是一个例子。

编辑...

在相关点上,我对使用 TSQL“扩展列”的不符合 ANSI 的查询的行为感到惊讶。 Sybase 处理 WHERE 子句 (ii) 之后的扩展列 (i) 通过创建与原始表的额外连接和 (iii) WHERE连接中不使用子句。此类查询可能返回比预期更多的行,然后 HAVING 子句需要额外的条件来过滤掉这些。

查看示例 bcd 在您最初链接的 docco 页面上的 “Transact-SQL extensions to group by and have” 下。我发现从 Sybase 安装 pubs2 示例数据库以与示例一起使用很有用。

【讨论】:

  • 感谢您提醒我注意以下语言。这正是我需要看到和失踪的。即使 having 子句只测试行,group by 子句的存在或不存在都可能使它看起来像是在对组进行操作所以当我们在选择列表中取消分组、未聚合的列时,组不再是单行 - 它是行数。并且 HAVING 适用于每一行。谢谢!
  • @Arkadiy,没问题。我编辑了我的答案并总结了一些我当时认为有用的附加信息。我希望它不会混淆原始 Q/A。
【解决方案2】:

我没有做过 Sybase,因为它与 MS SQL Server 共享代码....90 年代,但我对你所做的事情的解释是这样的:

首先,列表被过滤到

id   ts
1    2
1    10
2    5

其他所有内容都被过滤掉了。

接下来,您将列表过滤到 TS = 该组的 Max(TS) 的行。

id   ts
1    10
2    5

10 是第 1 组的 Max(TS),5 是第 2 组的 Max(TS)。这两行是剩下的。否则你会期待什么结果?

【讨论】:

  • 我确实看到它正在按照您的描述进行操作。但是,如果 HAVING 对组进行操作,那么它对 id == 1 的组有什么作用?要么必须包括整个组,因为它有一行匹配 HAVING 条件 (ts = 10),要么必须排除整个组,因为它有一行不匹配 HAVING 条件 (ts = 2)。我们在现实中所拥有的(以及您所描述的)是该组中的一些行被包括在内,一些被排除在外。我们在哪里看到描述的功能?这是我的问题。
【解决方案3】:

如果您阅读文档here,似乎Sybase 使用having 子句中未出现在group by 子句中的列与MySQL 不同。

他们给出的例子有这样的解释:

Transact-SQL 扩展列,价格(在选择列表中,但不是 一个聚合而不是在 group by 子句中),导致所有合格的 在每个合格组中显示的行,即使是标准组 by 子句每组产生一行。该组仍然影响 向量聚合,计算每组的平均价格 显示在每组的每一行(它们是相同的值 例如 a):

所以,ts = max(ts) 本质上是这样做的:

select *
from (select t.*,
             max(ts) over (partition by id) as maxts
      from #t
      where ts <= @time
     ) t
where ts = maxts

子查询很重要,因为where 子句用于max() 计算并且将返回所有行。

我发现这种行为相当混乱且不标准。我会用更典型的结构来代替它。它们的复杂程度大致相同,并且对于更多的受众来说似乎更清晰。

【讨论】:

    猜你喜欢
    • 2017-10-07
    • 2013-05-12
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 2015-05-23
    • 2010-11-14
    • 2020-06-10
    相关资源
    最近更新 更多