Omr*_*mri 19 sql-server window-functions sql-server-2014
我正在尝试将查询从 Oracle 迁移到 SQL Server 2014。
这是我在 Oracle 中运行良好的查询:
select
count(distinct A) over (partition by B) / count(*) over() as A_B
from MyTable
Run Code Online (Sandbox Code Playgroud)
这是我尝试在 SQL Server 2014 中运行此查询后遇到的错误。
Use of DISTINCT is not allowed with the OVER clause
Run Code Online (Sandbox Code Playgroud)
有谁知道是什么问题?在 SQL Server 中可以进行这种查询吗?请指教。
小智 18
这给出了由 B 分区的 A 的不同计数(*):
dense_rank() over (partition by B order by A)
+ dense_rank() over (partition by B order by A desc)
- 1
Run Code Online (Sandbox Code Playgroud)
Mar*_*ith 13
有谁知道是什么问题?在 SQL Server 中可以进行这种查询吗?
不,目前尚未实施。请参阅以下连接项目请求。
OVER 子句增强请求 - 聚合函数的 DISTINCT 子句
另一种可能的变体是
SELECT M.A,
M.B,
T.A_B
FROM MyTable M
JOIN (SELECT CAST(COUNT(DISTINCT A) AS NUMERIC(18,8)) / SUM(COUNT(*)) OVER() AS A_B,
B
FROM MyTable
GROUP BY B) T
ON EXISTS (SELECT M.B INTERSECT SELECT T.B)
Run Code Online (Sandbox Code Playgroud)
强制转换NUMERIC
是为了避免整数除法。此处解释了加入子句的原因。
它可以替换为ON M.B = T.B OR (M.B IS NULL AND T.B IS NULL)
if preferred (或者只是ON M.B = T.B
如果该B
列不可为空)。
您可以取 的最大值dense_rank()
来获得由 B 分区的 A 的非重复计数。
为了处理 A 可以具有空值的情况,您可以使用它first_value
来确定分区中是否存在空值,然后如果按照 Martin Smith 在评论中的建议减去 1。
select (max(T.DenseRankA) over(partition by T.B) -
cast(iif(T.FirstA is null, 1, 0) as numeric(18, 8))) / T.TotalCount as A_B
from (
select dense_rank() over(partition by T.B order by T.A) DenseRankA,
first_value(T.A) over(partition by T.B order by T.A) as FirstA,
count(*) over() as TotalCount,
T.A,
T.B
from MyTable as T
) as T
Run Code Online (Sandbox Code Playgroud)
尝试执行子查询,按 A、B 分组并包括计数。然后在您的外部查询中,您的 count(distinct) 变为常规计数,而您的 count(*) 变为 sum(cnt)。
select
count(A) over (partition by B) * 1.0 /
sum(cnt) over() as A_B
from
(select A, B, count(*) as cnt
from MyTable
group by A, B) as partial;
Run Code Online (Sandbox Code Playgroud)