SQL选择日期范围的第一个值和最后一个值

标签 sql sql-server tsql

我是 SQL 查询的新手,我需要从这个查询开始进行连接:

SELECT b.Name, a.*
FROM a INNER JOIN b ON a.VId = b.Id
WHERE  b.SId = 100
       AND a.Day >= '2016-05-05'
       AND a.Day < '2016-05-09';

并向第一个选定数据(表 c 中的 SCap 和 ECap)添加 2 个列。 根据我的尝试,我的代码如下所示:

    SELECT b.Name,a.*,
       c.MaxDay,
       c.Cap,
FROM   a INNER JOIN b
       ON a.VId = b.Id
       INNER JOIN
       (SELECT   VId,
                 MAX(TimestampLocal) AS MaxDay,
                 CAST (TimestampLocal AS DATE) AS Day,
                 Cap,
        FROM Info
        GROUP BY VId, 
                 CAST (TimestampLocal AS DATE), 
                     Cap) AS c
       ON a.VId = c.VId
          AND a.Day = c.Day
WHERE  b.SId = 33
       AND a.Day >= '2016-05-05'
       AND a.Day < '2016-05-09';

但是我得到的行比需要的多。

我需要给定车辆在日期范围内最早和最新的 TimestampLocal。这将来自 Info 中的两条记录,每条记录都有其正确的 Cap 值。 例如: 我有两个名称,其值在表信息中持续 2 天(名称 1),而名称 2 只有一天:

- Day 1 2016-05-07:
    - Name 1: Values at 2:45, 10:10 and 3.10
    - Name 2: Values at 5:13 and 8:22
- Day 2 2016-05-09:
    - Name 1: Values at 4:13, 6:15 and 9:20

我需要显示(如果我选择 daterange:2016-05-052016-05-09)对于 SCap 的名称 1 从 2016-05 开始的值-07 从 2:45 开始,对于 ECap,从 2016-05-09 从 9:20 开始,对于名称 2,对于 SCap,从 2016-05-07 从 5:13 开始,对于 ECap,从 2016-05-07 开始从 8 点 22 分开始。这应该显示在 2 行中。

有没有一种方法可以将这两列添加到我的查询中,而无需为相同名称添加更多行?

编辑! 表 a 我有:

VId   | Day
5251  | 05/09/2016
5382  | 05/09/2016

表b:

Id    | Name
5251  | N1
5382  | N2

表信息:

VId   | TimestampLocal                      |  Cap
5251  | 2016-05-09 11:33:46.2000000 +03:00  |   0
5251  | 2016-05-09 11:37:11.4000000 +03:00  |   7
5251  | 2016-05-09 11:38:11.4000000 +03:00  |   4
5251  | 2016-05-09 11:39:11.7000000 +03:00  |   2
5382  | 2016-05-09 09:30:56.6000000 -04:00  |   5
5382  | 2016-05-09 09:31:56.6000000 -04:00  |   3

我需要显示 - 如果我选择从 2016-05-032016-05-10 的日期范围:

Id    | Name | SCap | ECap
5251  | N1   | 0    | 2
5382  | N2   | 5    | 3

最佳答案

您可以使用 CTEROW_NUMBER 来检索两条记录:

;WITH Info_CTE AS (
   SELECT   VId,            
            CAST (TimestampLocal AS DATE) AS Day,
            Cap,
            ROW_NUMBER() OVER (PARTITION BY VId 
                               ORDER BY TimestampLocal) AS rn1,
            ROW_NUMBER() OVER (PARTITION BY VId 
                               ORDER BY TimestampLocal DESC) AS rn2
   FROM Info
)
SELECT b.Name,
       a.*,
       c.Day,
       c.Cap
FROM  a 
INNER JOIN b ON a.VId = b.Id
INNER JOIN Info_CTE AS c ON a.VId = c.VId AND 
                            a.Day = c.Day AND
                            1 IN (c.rn1, c.rn2)
WHERE  b.SId = 33
       AND a.Day >= '2016-05-05'
       AND a.Day < '2016-05-09';

如果您希望将 ECapSCap 作为单独的列,则不要使用

c.Cap

你可以使用:

CASE WHEN c.rn1 = 1 THEN c.Cap END AS ECap,
CASE WHEN c.rn2 = 1 THEN c.Cap END AS SCap

关于SQL选择日期范围的第一个值和最后一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37118851/

相关文章:

java - 如何在左侧填充连字符: Oracle

sql-server - 如何手动删除SSRS中的订阅?

php - MySQL 天数减法在月底不起作用

sql - 在一个很长的sql文件中查找第n个查询

sql - 具有非基于时间的开始和结束列的表中的组范围

sql-server-2008 - 在表值函数中使用临时表

sql - sql查询中where子句中的CASE语句

sql-server - 无法连接 AWS - RDS DB : SQL Server 2012 Express

sql-server - SQL Server 2012 更改数据捕获错误 14234

sql-server - 如何在 SQL Server 中将文本数据更改为数字?