Sql 从标识符中选择10 Before和10 After

Sql 从标识符中选择10 Before和10 After,sql,sql-server,tsql,sql-server-2008-r2,Sql,Sql Server,Tsql,Sql Server 2008 R2,您是否认为下面的SQL语句可以以比当前更好的方式执行 以下是要求: 查询需要TextIdentifier和用户名 确定之前创建的10个MP3文件和之后创建的10个MP3文件。 如果之前或之后存在的MP3文件少于10个,则选择所有可用文件。 无法使用表中的自动编号ID,因为创建的日期不相关 代码在图片下面 以下是一些潜在的场景: 查询: 测试数据 手头没有运行SQL Server 2008的盒子,但我检查了以下所有功能是否在2008年可用: DECLARE @UserName NVAR

您是否认为下面的SQL语句可以以比当前更好的方式执行

以下是要求:

查询需要TextIdentifier和用户名 确定之前创建的10个MP3文件和之后创建的10个MP3文件。 如果之前或之后存在的MP3文件少于10个,则选择所有可用文件。 无法使用表中的自动编号ID,因为创建的日期不相关 代码在图片下面

以下是一些潜在的场景:

查询:

测试数据


手头没有运行SQL Server 2008的盒子,但我检查了以下所有功能是否在2008年可用:

DECLARE @UserName       NVARCHAR(255) = 'Pete'
DECLARE @TextIdentifier NVARCHAR(255) = '456'

;WITH
    cte1 AS
    (
        SELECT      *,
                    ROW_NUMBER() OVER (ORDER BY DateCreated) AS RowNumber
        FROM        ProximitySelectTable
    ),
    cte2 AS
    (
        SELECT TOP 1
                    RowNumber
        FROM        cte1
        WHERE       UserName = @UserName AND TextIdentifier = @TextIdentifier
        ORDER BY    RowNumber
    )


SELECT      *
FROM        cte1, cte2
WHERE       cte1.RowNumber BETWEEN (cte2.RowNumber - 10) AND (cte2.RowNumber + 10)

cte1对从1到n的所有行进行编号。cte2查找目标行的行号。最后选择只需扫描过去10行和接下来10行。

以下是行号解决方案的伪代码:

WITH cte1 AS (
SELECT desiredcolumns, ROW_NUMBER() OVER (ORDER BY DateCol) AS rn
FROM MyTable
),
cte2 AS (
SELECT ID, rn
FROM cte1
WHERE TextIdentifier = @TextIdentifier 
)
SELECT desiredcolumns
FROM cte1
CROSS JOIN cte2
WHERE cte1.rn > cte2.rn - 10
AND cte1.rn < cte2.rn + 9

您当前的查询不正确,缺少ORDER BY和不需要的UNION而不是UNION ALL,但使用正确的索引,它的固定版本可能是最有效的

我的排号第一个答案是

WITH CTE1
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY DateCreated) AS RN
         FROM   [ProximitySelectTable]
         WHERE  UserName = @UserName),
     CTE2
     AS (SELECT *,
                MAX(CASE
                      WHEN @TextIdentifier = TextIdentifier
                        THEN RN
                    END) OVER () AS FocusRN
         FROM   CTE1)
SELECT ID,
       TextIdentifier,
       UserName,
       FileName,
       DateCreated
FROM   CTE2
WHERE  RN BETWEEN FocusRN - 10 AND FocusRN + 10
ORDER  BY DateCreated 
以及当前查询的固定版本

SELECT * FROM (
SELECT TOP 10 *
FROM    dbo.ProximitySelectTable
WHERE   UserName = @UserName
        AND [DateCreated] < @ProximityDate
ORDER BY [DateCreated] DESC 
UNION ALL
SELECT  *
FROM    dbo.ProximitySelectTable
WHERE   UserName = @UserName
        AND TextIdentifier = @TextIdentifier                      
UNION ALL
SELECT TOP 10 *
FROM    dbo.ProximitySelectTable
WHERE   UserName = @UserName
        AND [DateCreated] > @ProximityDate  
ORDER BY [DateCreated] ASC            
) x
ORDER BY x.DateCreated

这将需要一个关于用户名的索引,初始搜索的TextIdentifier,以及通过搜索和不排序获得前10名的DateCreated。

表上有哪些索引?我将研究一个使用行号的解决方案。表是全新的,还没有索引。这基本上是可行的,尽管从OP的初始代码来看,行编号应该应用于与用户匹配的行,因此cte1需要对UserName=@UserName进行筛选。与我的答案中的MAX-OVER相比,它的缺点是行编号会重复两次,因此您可以对整个表进行两次排序
WITH cte1 AS (
SELECT desiredcolumns, ROW_NUMBER() OVER (ORDER BY DateCol) AS rn
FROM MyTable
),
cte2 AS (
SELECT ID, rn
FROM cte1
WHERE TextIdentifier = @TextIdentifier 
)
SELECT desiredcolumns
FROM cte1
CROSS JOIN cte2
WHERE cte1.rn > cte2.rn - 10
AND cte1.rn < cte2.rn + 9
WITH CTE1
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY DateCreated) AS RN
         FROM   [ProximitySelectTable]
         WHERE  UserName = @UserName),
     CTE2
     AS (SELECT *,
                MAX(CASE
                      WHEN @TextIdentifier = TextIdentifier
                        THEN RN
                    END) OVER () AS FocusRN
         FROM   CTE1)
SELECT ID,
       TextIdentifier,
       UserName,
       FileName,
       DateCreated
FROM   CTE2
WHERE  RN BETWEEN FocusRN - 10 AND FocusRN + 10
ORDER  BY DateCreated 
SELECT * FROM (
SELECT TOP 10 *
FROM    dbo.ProximitySelectTable
WHERE   UserName = @UserName
        AND [DateCreated] < @ProximityDate
ORDER BY [DateCreated] DESC 
UNION ALL
SELECT  *
FROM    dbo.ProximitySelectTable
WHERE   UserName = @UserName
        AND TextIdentifier = @TextIdentifier                      
UNION ALL
SELECT TOP 10 *
FROM    dbo.ProximitySelectTable
WHERE   UserName = @UserName
        AND [DateCreated] > @ProximityDate  
ORDER BY [DateCreated] ASC            
) x
ORDER BY x.DateCreated