1

我遇到了以下 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 对组进行操作”。我在文档中看到的最接近的是:

have 子句可以包括不在选择列表中和 group by 子句中的列或表达式。

(从这里引用)。

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

4

3 回答 3

1

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

首先,列表被过滤为 <= 11

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)。这两行是剩下的行。否则你会期待什么结果?

于 2013-03-19T19:11:16.857 回答
1

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

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

Transact-SQL 扩展列 price(在选择列表中,但不是聚合且不在 group by 子句中)导致所有合格的行显示在每个合格的组中,即使标准的 group by 子句每次生成一行团体。group 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()计算并且将返回所有行。

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

于 2013-03-19T20:39:21.167 回答
1

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

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

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

其次,一个简短的摘要出现在“拥有,分组依据和位置子句如何相互作用”部分中:-

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

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

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

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

编辑...

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

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

于 2013-04-11T10:40:55.480 回答