通过过滤在组内选择
Selecting within group with filtering
假设我有以下 table / 数据:
create table #a(id int, name varchar(2), score int)
go
insert #a values(0, 'a1', 1)
insert #a values(1, 'b1', 0)
insert #a values(2, 'c1', 1)
insert #a values(3, 'd1', 0)
insert #a values(4, 'd2', 1)
insert #a values(5, 'e1', 0)
insert #a values(6, 'e2', 2)
insert #a values(7, 'e3', 1)
insert #a values(8, 'e4', 0)
我想select这些行:
id name score
1 b1 0
2 c1 1
4 d2 1
6 e2 2
条件:
- 只有 id > 0
- 按姓名首字母分组
- 每组最高分
- 决胜局,最高名称(ASCII 排序)
这是我想出的:
select id, name, score
into #b
from #a
where id > 0
group by left(name, 1)
having score = max(score)
go
select f.*
from #b f
left join #b g on left(g.name, 1) = left(f.name, 1) and g.name > f.name
where g.name is null
order by f.name
在不使用临时 table / 两次查询 / 重复(所有这些 left
s)和总体效率方面可以做得更好吗?
使用row_number()
:
select a.*
from (select a.*,
row_number() over (partition by left(name, 1)
order by score desc, name asc
) as seqnum
from #a a
) a
where seqnum = 1;
编辑:
某些版本的 Sybase 确实支持 row_number()
,但不是全部。您还可以:
select a.*
from #a a
where a.id = (select top 1 a2.id
from #a a2
where left(a2.name, 1) = left(a.name, 1)
order by a2.score desc, name asc
);
编辑二:
这个有用吗?
select a.*
from (select a.*,
(select top 1 a2.id
from #a a2
where left(a2.name, 1) = left(a.name, 1)
order by a2.score desc, name asc
) as comp_id
from #a a
) a
where id = comp_id;
即TOP
在SELECT
的子查询中是否允许?
假设
name
是独一无二的
为了测试决胜逻辑,我们将添加另一个 'e' 行:
insert #a values (9,'e5',2) -- same score as the 6/e2/2 record
因为 SAP(Sybase) ASE 有很多限制...
- 不支持
rank()
函数
- 不支持
row_number()
函数
- 不支持
offset/limit
子句
- 子查询中对
top
子句的有限支持
- 不支持子查询中的
order by
子句
...我们需要了解一点 'creative'(阅读:这会变得有点复杂)
我们要做的第一件事是找到每个单个字符的最大分数,其中 id > 0:
select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)
order by 1
go
name1 mscore
----- -----------
b 0
c 1
d 1
e 2
接下来我们将把这个结果集与原始 table 相结合,根据第一个字符和 score = max(score):
匹配行
select a2.name1,
a1.name,
a2.mscore
from #a a1
join (select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)) a2
on left(a1.name,1) = a2.name1
and a1.score = a2.mscore
and a1.id > 0
order by 1,2
go
name1 name mscore
----- ---- -----------
b b1 0
c c1 1
d d2 1
e e2 2
e e5 2
接下来我们将讨论决胜规则;我们可以通过将 max()
函数应用到我们的 a1.name
列来处理这个问题(确保添加适当的 group by
子句):
select a2.name1,
max(a1.name) as mname,
a2.mscore
from #a a1
join (select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)) a2
on left(a1.name,1) = a2.name1
and a1.score = a2.mscore
and a1.id > 0
group by a2.name1,
a2.mscore
order by 1,2
go
name1 mname mscore
----- ----- -----------
b b1 0
c c1 1
d d2 1
e e5 2
拼图的最后一部分是将这个最终结果与原始table联系起来以获得id:
select a3.id,
a4.mname as 'name',
a4.mscore as 'score'
from #a a3
join (select a2.name1,
max(a1.name) as mname,
a2.mscore
from #a a1
join (select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)) a2
on left(a1.name,1) = a2.name1
and a1.score = a2.mscore
and a1.id > 0
group by a2.name1,
a2.mscore) a4
on a3.name = a4.mname
order by 1,2
go
id name score
----------- ---- -----------
1 b1 0
2 c1 1
4 d2 1
9 e5 2
注意:以上 queries/results 在 SAP(Sybase) ASE 16.0 SP03 PL01 上验证。
最终结果...
虽然可以通过单个查询完成所需的操作,但编码有点复杂(并且可能更难维护)。
原始代码(2 个查询和一个中间临时 table)更容易理解(并且可能更容易维护)。
假设我有以下 table / 数据:
create table #a(id int, name varchar(2), score int)
go
insert #a values(0, 'a1', 1)
insert #a values(1, 'b1', 0)
insert #a values(2, 'c1', 1)
insert #a values(3, 'd1', 0)
insert #a values(4, 'd2', 1)
insert #a values(5, 'e1', 0)
insert #a values(6, 'e2', 2)
insert #a values(7, 'e3', 1)
insert #a values(8, 'e4', 0)
我想select这些行:
id name score
1 b1 0
2 c1 1
4 d2 1
6 e2 2
条件:
- 只有 id > 0
- 按姓名首字母分组
- 每组最高分
- 决胜局,最高名称(ASCII 排序)
这是我想出的:
select id, name, score
into #b
from #a
where id > 0
group by left(name, 1)
having score = max(score)
go
select f.*
from #b f
left join #b g on left(g.name, 1) = left(f.name, 1) and g.name > f.name
where g.name is null
order by f.name
在不使用临时 table / 两次查询 / 重复(所有这些 left
s)和总体效率方面可以做得更好吗?
使用row_number()
:
select a.*
from (select a.*,
row_number() over (partition by left(name, 1)
order by score desc, name asc
) as seqnum
from #a a
) a
where seqnum = 1;
编辑:
某些版本的 Sybase 确实支持 row_number()
,但不是全部。您还可以:
select a.*
from #a a
where a.id = (select top 1 a2.id
from #a a2
where left(a2.name, 1) = left(a.name, 1)
order by a2.score desc, name asc
);
编辑二:
这个有用吗?
select a.*
from (select a.*,
(select top 1 a2.id
from #a a2
where left(a2.name, 1) = left(a.name, 1)
order by a2.score desc, name asc
) as comp_id
from #a a
) a
where id = comp_id;
即TOP
在SELECT
的子查询中是否允许?
假设
name
是独一无二的
为了测试决胜逻辑,我们将添加另一个 'e' 行:
insert #a values (9,'e5',2) -- same score as the 6/e2/2 record
因为 SAP(Sybase) ASE 有很多限制...
- 不支持
rank()
函数 - 不支持
row_number()
函数 - 不支持
offset/limit
子句 - 子查询中对
top
子句的有限支持 - 不支持子查询中的
order by
子句
...我们需要了解一点 'creative'(阅读:这会变得有点复杂)
我们要做的第一件事是找到每个单个字符的最大分数,其中 id > 0:
select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)
order by 1
go
name1 mscore
----- -----------
b 0
c 1
d 1
e 2
接下来我们将把这个结果集与原始 table 相结合,根据第一个字符和 score = max(score):
匹配行select a2.name1,
a1.name,
a2.mscore
from #a a1
join (select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)) a2
on left(a1.name,1) = a2.name1
and a1.score = a2.mscore
and a1.id > 0
order by 1,2
go
name1 name mscore
----- ---- -----------
b b1 0
c c1 1
d d2 1
e e2 2
e e5 2
接下来我们将讨论决胜规则;我们可以通过将 max()
函数应用到我们的 a1.name
列来处理这个问题(确保添加适当的 group by
子句):
select a2.name1,
max(a1.name) as mname,
a2.mscore
from #a a1
join (select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)) a2
on left(a1.name,1) = a2.name1
and a1.score = a2.mscore
and a1.id > 0
group by a2.name1,
a2.mscore
order by 1,2
go
name1 mname mscore
----- ----- -----------
b b1 0
c c1 1
d d2 1
e e5 2
拼图的最后一部分是将这个最终结果与原始table联系起来以获得id:
select a3.id,
a4.mname as 'name',
a4.mscore as 'score'
from #a a3
join (select a2.name1,
max(a1.name) as mname,
a2.mscore
from #a a1
join (select left(name,1) as name1,
max(score) as mscore
from #a
where id > 0
group by left(name,1)) a2
on left(a1.name,1) = a2.name1
and a1.score = a2.mscore
and a1.id > 0
group by a2.name1,
a2.mscore) a4
on a3.name = a4.mname
order by 1,2
go
id name score
----------- ---- -----------
1 b1 0
2 c1 1
4 d2 1
9 e5 2
注意:以上 queries/results 在 SAP(Sybase) ASE 16.0 SP03 PL01 上验证。
最终结果...
虽然可以通过单个查询完成所需的操作,但编码有点复杂(并且可能更难维护)。
原始代码(2 个查询和一个中间临时 table)更容易理解(并且可能更容易维护)。