【问题标题】:SQL select items between LAG and LEAD using as rangeSQL 使用范围选择 LAG 和 LEAD 之间的项目
【发布时间】:2018-02-11 10:11:31
【问题描述】:

是否可以使用 Lag 从一个表中选择和汇总项目,并从另一个表中获取如下范围。

SELECT @Last  = MAX(ID) from [dbo].[#Temp] 
     select  opl.Name  as [Age Categories] ,  
     ( SELECT count([dbo].udfCalculateAge([BirthDate],GETDATE())) 
       FROM    [dbo].[tblEmployeeDetail] ed  
       inner join  [dbo].[tblEmployee] e 
       on   ed.EmployeeID = e.ID 
      where    convert(int,[dbo].udfCalculateAge(e.[BirthDate],GETDATE()))
             between LAG(opl.Name) OVER (ORDER BY opl.id)   
                 and (CASE opl.ID WHEN   @Last  THEN '100'  ELSE  opl.Name End ) 
     )  as Total
FROM [dbo].[#Temp] opl 

tblEmployee 包含员工及其出生日期

  INSERT INTO @tblEmployees VALUES
(1, 'A', 'A1', 'A', '1983/01/02'),
(2, 'B', 'B1', 'BC', '1982/01/02'),
(3, 'C', 'C1', 'JR2', '1982/10/11'),
(4, 'V', 'V1', 'G', '1990/07/12'),
(5, 'VV', 'VV1', 'J', '1992/06/02'),
(6, 'R', 'A', 'D', '1982/05/15'),
(7, 'C', 'Ma', 'C', '1984/09/29')

下一个表是根据用户输入的年龄创建的临时表,例如“20;30;50;60”使用函数拆分在下面生成一个临时表

 select * FROM  [dbo].[Split](';','20;30;50;60') 

临时表

pn  s
1   20
2   30
3   50
4   60

所需的输出如下,尽管列 Age Categories 可以在 C# 的数据表中重命名。 l 需要总列在范围上是准确的。

Age Categories      Total
up to 20            0
21 - 30             2
31 - 50             5
51 - 60             0

【问题讨论】:

  • 请显示您的样本数据和预期结果,以便我们评估您的问题
  • 希望现在有点清楚了。

标签: sql sql-server tsql lag lead


【解决方案1】:

这些方面的东西应该适合你:

declare @tblEmployees table(
ID int,    
FirstNames varchar(20),       
Surname varchar(20),     
Initial varchar(3),    
BirthDate date)

INSERT INTO @tblEmployees VALUES
(1, 'A', 'A1', 'A', '1983/01/02'),
(2, 'B', 'B1', 'BC', '1982/01/02'),
(3, 'C', 'C1', 'JR2', '1982/10/11'),
(4, 'V', 'V1', 'G', '1990/07/12'),
(5, 'VV', 'VV1', 'J', '1992/06/02'),
(6, 'R', 'A', 'D', '1982/05/15'),
(7, 'C', 'Ma', 'C', '1984/09/29')

declare @temp table
(id int identity,
age int)

INSERT INTO @temp 
SELECT cast(item as int) FROM dbo.fnSplit(';','20;30;50;60')

declare @today date = GetDate()
declare @minBirthCutOff date = (SELECT DATEADD(yy, -MAX(age), @today) FROM @temp)
declare @minBirth date = (SELECT Min(birthdate) from @tblEmployees)
IF @minBirth < @minBirthCutOff
    BEGIN
        INSERT INTO @temp VALUES (100)
    end
SELECT COALESCE(CAST((LAG(t.age) OVER(ORDER BY t.age) + 1) as varchar(3)) 
+ ' - ','Up to ') 
       + CAST(t.age AS varchar(3)) AS [Age Categories], 
       COUNT(e.id) AS [Total] FROM @temp t
LEFT JOIN
(SELECT te.id, 
       te.age, 
       (SELECT MIN(age) FROM @temp t WHERE t.age > te.age) AS agebucket
FROM (select id, 
      dbo.udfCalculateAge(birthdate,@today) age from @tblEmployees) te) e
ON e.agebucket = t.age
GROUP BY t.age ORDER BY t.age

结果集如下所示:

Age Categories  Total
Up to 20    0
21 - 30 2
31 - 50 5
51 - 60 0

供将来参考,特别是在询问 SQL 问题时,如果您提供我所做的大部分工作,您将获得更快更好的响应。即为相关表创建语句并插入语句以提供示例数据。你这样做比我们容易得多(我们必须复制和粘贴,然后重新格式化等),而你应该能够通过一些选择 SELECT 语句来做同样的事情!

还请注意,当生日超出给定范围时,我处理的情况完全不同。通过 MAX 进行一次检查比使 SELECT 语句复杂化更有效。它也使它更具可读性。

感谢 HABO 对 GetDate() 的建议

【讨论】:

  • 谢谢,它成功地融入了我的存储过程。
  • 提示:GetDate() 在查询中的处理方式有点奇怪。每个 instance 在查询中都有一个常量值。例如select GetDate() as D1, GetDate() as D2 from SomeTable 可能会为两列返回两个不同的值,但它们不会因一行而异。在多个语句中使用 GetDate() 时,例如在存储过程中,可以通过获取单个值并在整个过程中使用它来避免有趣的意外,即declare @Now as DateTime = GetDate(); 并根据需要使用@Now
  • @HABO 很好,我会相应地编辑答案。谢谢
猜你喜欢
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多