我想知道是否可以使用over (partition by...)
子句以避免在下面的示例中使用子选择:
declare @t table (
id int
,code char(2)
,descriptor int
)
insert into @t
select 1, 'a1', 10
union select 1, 'a1', 20
union select 1, 'a1', 30
union select 2, 'b1', 10
union select 2, 'b1', 20
union select 2, 'b1', 30
union select 2, 'b2', 10
union select 2, 'b2', 20
union select 2, 'b2', 30
union select 3, 'c4', 10
union select 3, 'c4', 20
union select 3, 'c4', 30
union select 3, 'c7', 10
union select 3, 'c7', 20
union select 3, 'c7', 30
select *
from @t as t
where code = (select min(code) from @t where id = t.id)
我只想查看code
等于a1
和b1
的记录c4
。可以over (partition by...)
将 1 分配给所有这些,将 2 分配给代码b2
等c7
,这样最后我可以说where row_number = 1
而不是使用子查询?
是的,但不是
row_number()
。您可以使用窗口聚合min()
:或
rank()
窗口函数(或其中dense_rank()
一个,它们在rnk = 1
检查中的工作方式相同):我正要评论说,如果没有任何类型的子查询(相关的、派生的表、ctes),就没有办法做到这一点,但唉,有。不是在 2008R2 中,而是在 2012 版本中使用了更多的窗口函数。
注意:不要使用这个。效率可能会更差。以下查询可能适用于混淆竞赛,但不适用于生产。
相反,当有合适的索引时,检查上述第二个查询的好执行计划。
只是为了好玩 - 以及对代码未来维护者的恐惧:
在SQLFiddle测试
另一种方式(满足要求并与 2005+ 兼容,但可能永远不会在实践中使用)是
虽然以这种方式使用有趣的答案(ab)
TOP
不如简单地使用某种形式的派生表并在其中进行过滤WHERE
。无论如何,如果不将其包装在表表达式中,您将无法对该查询的结果应用任何额外的排序。因为电流
ORDER BY
必须保持不变以避免改变结果。SQL小提琴
当然,您也可以使用 CTE 编写此代码:
你不能说:
因为:
完全不清楚这一点:
但是,也许谁盲目地拒绝子查询的想法,就不会明智地认识到 CTE 只是不同服装的子查询。(事实上很多人都没有认出 CTE,这有时既是福也是祸。)
否则,请重新开始,并解释为什么需要完全删除子查询。对于某些问题(如应用窗口函数),除了在不同的范围内过滤它们之外别无选择——这意味着子查询、派生表、CTE 等......所有子查询的风格。
order by仅用于以与您的示例相同的顺序生成输出表,但这完全没有必要。
修订以包括我在下面添加的评论 - 处理重复项:
没有子选择,没有 SQL 2012 的特殊功能。只是 SQL。可以办到。