you*_*gme 7 sql-server t-sql window-functions
我看到了一个简洁的 TSQL 语句,它有效地将字符串拆分为其组成字符,每行一个,目的是评估ascii
每个字符的值。
如果我正确地、有效地阅读了查询,将使用 3 个 CTE 来准备一个包含 10,000 行的 1 列表,每行的值为“0”。
第四个 CTE 定义如下:
cteTally(n) AS(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) n
FROM E4
)
Run Code Online (Sandbox Code Playgroud)
随后,这个 CTE 被连接到一个包含感兴趣字符串列的表中,如下所示select
:
SELECT n, SUBSTRING(LastName, n, 1), ASCII( SUBSTRING(LastName, n, 1))
Run Code Online (Sandbox Code Playgroud)
也就是说,行号 n,然后是 LastName 中的第 n 个字符,然后是该字符的 ascii 值。
我的问题与over
上述 CTE 中的条款有关。
本质上,它到底在做什么?
如果我们从 10,000 个相同的行中查询 row_number,为什么我们根本需要一个order by
子句?为什么order by
放入over
条款,而不是作为一个order by
在子句select
声明-尤其是在over
条款甚至没有指定任何分区?(我认为这意味着操作的窗口row_number
是完整的 10,000 行?)排序是select null
什么意思?
ROW_NUMBER() 是一个排名窗口函数,排名窗口函数需要一个强制的 ORDER BY 子句。如果您尝试在没有 ORDER BY 的情况下编写它,则会出现语法错误。
SELECT ROW_NUMBER() OVER()
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 4112, Level 15, State 1, Line 1
-- The function 'ROW_NUMBER' must have an OVER clause with ORDER BY.
Run Code Online (Sandbox Code Playgroud)
使用子查询的技巧是由写博客的人发现的,作为性能优化。SQL Server 总是执行排序操作,因为 ORDER BY 子句不允许使用常量:
SELECT ROW_NUMBER() OVER(ORDER BY NULL)
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 5309, Level 16, State 1, Line 1
-- Windowed functions, aggregates and NEXT VALUE FOR functions
-- do not support constants as ORDER BY clause expressions.
Run Code Online (Sandbox Code Playgroud)
也不是整数,它们被视为索引:
SELECT ROW_NUMBER() OVER(ORDER BY 1)
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 5308, Level 16, State 1, Line 1
-- Windowed functions, aggregates and NEXT VALUE FOR functions
-- do not support integer indices as ORDER BY clause expressions.
Run Code Online (Sandbox Code Playgroud)
事实证明,由于代码中的一些小故障,您可以通过使用子查询来规避此限制,出于某种原因,子查询是允许的,并消除了排序运算符。
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
Run Code Online (Sandbox Code Playgroud)
您可以在子查询中使用任何常量,NULL 可能让人想起在 EXISTS 谓词中使用 SELECT NULL 的习惯,在 SQL Server 的早期历史中,与 * 或任何其他列表达式相比,这对性能有影响,如优化器不够聪明,无法忽略它。
HTH
UPDATE @Erik-Darling 评论说您也可以通过使用计算表达式来规避它:
You can do SELECT ROW_NUMBER() OVER (ORDER BY 1/0);
Run Code Online (Sandbox Code Playgroud)