我遇到了以下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)。
然而,他们并没有准确解释当你这样做时会发生什么。
答案 0 :(得分:1)
我没有完成Sybase,因为它与MS SQL Server共享代码.... 90年代,但我对你所做的解释是:
首先,列表被过滤为&lt; = 11
id ts
1 2
1 10
2 5
其他所有内容都被过滤掉了。
接下来,您将列表过滤到TS =该组的最大值(TS)的行。
id ts
1 10
2 5
10是组1的最大值(TS),5是组2的最大值(TS)。这两行是剩余的行。你会有什么结果呢?
答案 1 :(得分:1)
如果您阅读文档here,则having
子句中未出现在group by
子句中的Sybase使用的列似乎与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()
计算和将返回所有行。
我发现这种行为相当混乱和不标准。我会用更典型的结构替换它。这些复杂程度大致相同,对更多的受众来说似乎更清晰。
答案 2 :(得分:1)
我的理解:是的,从根本上说,HAVING在行上运行。通过省略GROUP BY,它可以在单个“超级组”内的所有结果行上操作,而不是在组内的行上操作。阅读原始链接的Sybase docco中的“如何分组并使用聚合查询工作”部分: -
如何分组和查询聚合工作
- where 子句排除不符合搜索条件的行;对于分组或非分组查询,其功能保持不变。
- group by 子句将剩余的行收集到组中表达式中的每个唯一值的一个组中。省略分组可为整个表创建一个组。
- 选择列表中指定的聚合函数计算每个组的汇总值。对于标量聚合,表只有一个值。向量聚合计算不同组的值。
- 有子句从结果中排除不符合其搜索条件的组。即使具有子句仅测试行, group by 子句的存在与否也可能使其看起来在组上运行:
- 当查询包含分组时, 会排除结果组行。这就是 似乎对群组进行操作的原因。
- 如果查询没有分组,则 会从(单组)表中排除结果行。这就是 似乎对行进行操作的原因(结果类似于 where 子句的结果)。
其次,简要摘要出现在"How the having, group by, and where clauses interact"部分: -
拥有,分组和where子句如何互动
如果在查询中包含拥有,分组和其中子句,则每个子句影响行的顺序决定最终结果:
- where 子句排除不符合其搜索条件的行。
- group by 子句将剩余的行收集到组表达式中的每个唯一值的一个组中。
- 选择列表中指定的聚合函数计算每个组的汇总值。
- 有子句会排除最终结果中不符合搜索条件的行。
@ SQLGuru的解释是对此的一个例证。
在相关的一点上,我对使用TSQL“扩展列”的非ANSI符合查询的行为感到惊讶。 Sybase在WHERE子句(ii)之后处理扩展列(i),方法是创建对原始表的额外连接,(iii) WHERE在连接中不使用子句。这样的查询可能会返回比预期更多的行,然后HAVING子句需要额外的条件来过滤掉这些行。
查看示例 b , c 和 d 在“Transact-SQL扩展中,在原始链接的docco的页面上分组并拥有”。我发现从Sybase安装 pubs2 示例数据库与示例一起使用很有用。