SQL:给定行之前和之后的行

时间:2011-03-01 19:01:49

标签: sql

问题是我们要获得给定行之前和之后的总行数(例如,由主键标识)。

我在T-SQL(MSSQL 2008)中尝试了以下内容。它给出了正确的结果,但我不知道这是否是最好的方法。

;WITH cte_before AS 
(
    SELECT ROW_NUMBER() OVER ( Order By CustomerId ) [Row Number], customerid, 
           firstName 
    FROM SalesLT.Customer
 ),
cte_nums AS 
(
    SELECT ROW_NUMBER() OVER ( Order By CustomerId ) [Row Number1] 
    FROM SalesLT.Customer
)
SELECT [Row Number]-1 [before], MAX([Row Number1]) - [Row Number]
       , CustomerID, FirstName 
FROM cte_nums, cte_before
GROUP BY [Row Number], CustomerID, FirstName
HAVING CustomerID = 55

我们如何在T-SQL中改进它?我们如何在其他SQL方言和服务器(如Oracle,MySQL,sqlite,FireBird等)中完成它。

3 个答案:

答案 0 :(得分:2)

我认为这适用于任何方言:

select 
   (select count(*) from SalesLT.Customer where customerid < 55) as rows_before,
   (select count(*) from SalesLT.Customer where customerid > 55) as rows_after,
   CustomerID, FirstName
from SalesLT.Customer
where CustomerID = 55

答案 1 :(得分:1)

与菲利普的想法相同,但实施得当且经过测试。这仅使用库存标准ANSI SQL。

SELECT A.customerid, A.firstName,
  count(case when B.customerid < A.customerid then 1 end) count_before,
  count(case when B.customerid > A.customerid then 1 end) count_after
FROM SalesLT.Customer A
cross join SalesLT.Customer B
where A.customerID=55
GROUP BY A.customerid, A.firstName

“A”别名找到您想要的客户(55)。对B的连接为每个客户生成一行,为每行测试A.customerID。

CASE子句产生

  • 1;当条件<符合A.customerid [55]
  • null(没有ELSE子句时隐式)未满足时
  • Count会跳过空值,因此总计正确

GROUP BY需要使用COUNT(),一个聚合函数

答案 2 :(得分:0)

改进的SQL版本:

DECLARE @CustomerId int

SET @CustomerId = 55

SELECT
   @CustomerId
  ,ThisOne.FirstName
  ,sum(case when Agg.CustomerId < @CustomerId then 1 else 0 end)  [Before]
  ,sum(case when Agg.CustomerId > @CustomerId then 1 else 0 end)  [After]
 from SalesLT.Customer Agg
  inner join SalesLT.Customer ThisOne
   on ThisOne.CustomerId = @CustomerId