【问题标题】:SQL Select where first value and last value of daterangeSQL选择日期范围的第一个值和最后一个值
【发布时间】:2016-05-09 14:50:44
【问题描述】:

我是 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 仅 1 天:

- 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

我需要显示(如果我选择日期范围:2016-05-052016-05-09)对于 SCap 的名称 1 从 2:45 开始的 2016 年 5 月 7 日的值,对于 ECap 的从 2016 年 5 月 9 日的值9:20 和名称 2 的 SCap 从 2016 年 5 月 7 日的值从 5:13 开始,对于 ECap 的值从 2016 年 5 月 7 日从 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

【问题讨论】:

  • 你能展示一些示例数据和预期的结果吗?
  • @vkp - 我已经更新了我的问题

标签: sql sql-server tsql


【解决方案1】:

您可以使用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

【讨论】:

  • 当我尝试运行此代码时,我什么也没得到 :(
【解决方案2】:

首先,获取给定日期每个 id 的最大和最小时间戳。然后将它加入两次,一次是最大时间戳值,然后是每个 id 到 tblinfo 的最小时间戳值,以获取这些行的开始和结束上限值。

添加带有日期过滤器的where 子句以过滤特定日期。

Sample demo

with maxandmin as 
(select vid
        ,max(timestamplocal) maxtime
        ,min(timestamplocal) mintime
 from tblinfo
 group by vid,cast(timestamplocal as date))
select m.vid,b.name,i1.cap as Scap,i2.cap as Ecap
from maxandmin m 
join tblinfo i1 on m.vid=i1.vid and m.mintime = i1.timestamplocal
join tblinfo i2 on m.vid=i2.vid and m.maxtime = i2.timestamplocal
join tableb b on b.id=m.vid

【讨论】:

  • 必须改成i
  • 查看编辑后的版本是否有效。不得不更改查询。
  • 我尝试为 2 个不同的名称运行它,并且:我得到 6 行而不是只有 2 行,而且运行速度非常慢 :(
  • 我猜这是因为你得到了每一天的开始和结束时间。将输出中的日期列添加到检查中。根据你需要的问题。
【解决方案3】:

经过进一步调查后,我找到了我的查询的解决方案,这就是我设法做到的:

SELECT      b.Id,
            b.Name,
            c.S_Time,
            c.E_Time,
            s.Cap AS S_Cap,
            e.Capa AS E_Cap,
FROM        b
INNER JOIN   (SELECT  VId,
                     MIN(TimestampLocal) AS S_Time,
                     MAX(TimestampLocal) AS E_Time
            FROM     Info
            where CAST (TimestampLocal AS DATE) >='2016-04-05'
            and CAST (TimestampLocal AS DATE) <'2016-05-10'
            GROUP BY VId
            ) AS c
        ON  b.Id = c.VId
INNER JOIN   Info AS s
        ON  s.VId = c.VId
        AND s.TimestampLocal = c.S_Time
INNER JOIN   Info AS e
        ON  e.Vd = c.VId
        AND e.TimestampLocal = c.E_Time
WHERE   b.SId = 100

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-14
    • 2021-06-02
    • 2019-01-24
    • 1970-01-01
    • 2012-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多