创建一个子查询以过滤窗口函数值
Create a subquery to filter on windowed function value
我正在尝试向 EF Core 添加 ROW_NUMBER 功能并通过它进行过滤。
添加自定义函数后,它在 Select
中工作正常但在 Where
中不起作用,因为格式错误 SQL.
林克:
var query = dbContext.OrderItems
.Select(i => new
{
i.Name,
RowNumber = EF.Functions.RowNumber(i.ProductId)
})
.Where(i => i.RowNumber == 1);
转换为:
SELECT
i.NAME,
ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
FROM
OrderItems AS i
WHERE
ROW_NUMBER() OVER(ORDER BY i.ProductId) = CAST(1 AS bigint)
错误:
Microsoft.Data.SqlClient.SqlException (0x80131904): Windowed functions can only appear in the SELECT or ORDER BY clauses.
要更正此 SQL,我需要创建一个子查询:
SELECT
t.NAME,
t.RowNumber
FROM (
SELECT
i.NAME,
ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
FROM
OrderItems AS i
) t
WHERE
t.RowNumber = CAST(1 AS bigint)
我找到了一篇关于如何在 EF Core 2 中执行此操作的文章。
Probably, the easiest way is to introduce a method that gives EF a hint that the previous query should be a sub query. Fortunately, we don't have do much because internally the method AsQueryable (or rather the expression associated with it) does just that.
https://www.thinktecture.com/en/entity-framework-core/making-rownumber-more-useful-in-2-1/
但是这种方法在 EF Core 3.1 中没有任何作用
有没有办法创建子查询?
查看 EF Core 3.1 源代码,我看到在应用 where
过滤器之前强制执行子查询的唯一方法是引入查询限制(即 Skip
and/or Take
).
从两个可能的fake limit operators(Skip(0)
和Take(int.MaxValue)
)来看,选后者比较好,因为前者也需要一定的排序(甚至是fake)
所以解决方法是插入
.Take(int.MaxValue)
在 .Where(...)
之前。
生成的SQL并不完美(有伪造的TOP
子句),但至少是有效的。
我正在尝试向 EF Core 添加 ROW_NUMBER 功能并通过它进行过滤。
添加自定义函数后,它在 Select
中工作正常但在 Where
中不起作用,因为格式错误 SQL.
林克:
var query = dbContext.OrderItems
.Select(i => new
{
i.Name,
RowNumber = EF.Functions.RowNumber(i.ProductId)
})
.Where(i => i.RowNumber == 1);
转换为:
SELECT
i.NAME,
ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
FROM
OrderItems AS i
WHERE
ROW_NUMBER() OVER(ORDER BY i.ProductId) = CAST(1 AS bigint)
错误:
Microsoft.Data.SqlClient.SqlException (0x80131904): Windowed functions can only appear in the SELECT or ORDER BY clauses.
要更正此 SQL,我需要创建一个子查询:
SELECT
t.NAME,
t.RowNumber
FROM (
SELECT
i.NAME,
ROW_NUMBER() OVER(ORDER BY i.ProductId) AS RowNumber
FROM
OrderItems AS i
) t
WHERE
t.RowNumber = CAST(1 AS bigint)
我找到了一篇关于如何在 EF Core 2 中执行此操作的文章。
Probably, the easiest way is to introduce a method that gives EF a hint that the previous query should be a sub query. Fortunately, we don't have do much because internally the method AsQueryable (or rather the expression associated with it) does just that.
https://www.thinktecture.com/en/entity-framework-core/making-rownumber-more-useful-in-2-1/
但是这种方法在 EF Core 3.1 中没有任何作用
有没有办法创建子查询?
查看 EF Core 3.1 源代码,我看到在应用 where
过滤器之前强制执行子查询的唯一方法是引入查询限制(即 Skip
and/or Take
).
从两个可能的fake limit operators(Skip(0)
和Take(int.MaxValue)
)来看,选后者比较好,因为前者也需要一定的排序(甚至是fake)
所以解决方法是插入
.Take(int.MaxValue)
在 .Where(...)
之前。
生成的SQL并不完美(有伪造的TOP
子句),但至少是有效的。