【问题标题】:SQL: Show Records Once SUM Threshold Is ReachedSQL:达到 SUM 阈值后显示记录
【发布时间】:2018-07-31 21:03:54
【问题描述】:

我有一个表格,按日期值 (ASC) 排序。

+----+------------+-------+
| Id |    Date    | Value |
+----+------------+-------+
|  1 | 2018-01-01 |    10 |
|  2 | 2018-01-02 |     5 |
|  3 | 2018-01-03 |    15 |
|  4 | 2018-01-04 |     0 |
|  5 | 2018-01-05 |     5 |
|  6 | 2018-01-06 |    10 |
|  7 | 2018-01-07 |     5 |
|  8 | 2018-01-08 |     0 |
|  9 | 2018-01-09 |     0 |
| 10 | 2018-01-10 |    10 |
+----+------------+-------+

我想创建一个视图,从第一条记录开始,仅在 Value 的 SUM 高于 30 时才返回记录。 所以我的阈值是 30,每条具有适合前 30 的值的记录都应该被隐藏。 达到此阈值后的所有记录都需要显示。

这意味着我需要的结果如下所示:

+----+------------+-------+
| Id |    Date    | Value |
+----+------------+-------+
|  4 | 2018-01-04 |     0 |
|  5 | 2018-01-05 |     5 |
|  6 | 2018-01-06 |    10 |
|  7 | 2018-01-07 |     5 |
|  8 | 2018-01-08 |     0 |
|  9 | 2018-01-09 |     0 |
| 10 | 2018-01-10 |    10 |
+----+------------+-------+

如您所见,Id 的 1、2 和 3 被省略了,因为它们的值(10、5 和 15)总和为 30。 一旦达到这个阈值,剩下的记录就可见了(即使是 Id 4 的 0 值)。

我创建了一些脚本来设置带有数据的测试表:

-- Create test table
CREATE TABLE thresholdTest (
    [Id] INT IDENTITY(1,1) PRIMARY KEY,
    [Date] DATE NOT NULL,
    [Value] INT NOT NULL
)

-- Insert dummies
INSERT INTO [thresholdTest] ([Date],[Value])
VALUES
('2018-01-01',10),
('2018-01-02',5),
('2018-01-03',15),
('2018-01-04',0),
('2018-01-05',5),
('2018-01-06',10),
('2018-01-07',5),
('2018-01-08',0),
('2018-01-09',0),
('2018-01-10',10);

-- Select ordered by date
SELECT *
FROM [thresholdTest]
ORDER BY [Date] ASC

我只需要一个 SELECT 语句/视图。 阈值始终是静态的(本例中为 30)。 数据当然可以不同,但​​它总是按日期排序并包含一个值。

提前谢谢你。

【问题讨论】:

  • 除非在该列上创建聚集索引,否则您的表不会按日期值排序。正如您所写,它只是使用order by 在返回时进行排序。我只想强调这是非常不同的,许多人错误地认为他们的数据是按照插入的顺序在磁盘上排序的。没有聚集索引,这是不正确的。

标签: sql sql-server


【解决方案1】:

我会使用窗口函数:

;with cte as(
select *,  tot = sum([Value]) over (order by [Date])
from thresholdTest
)

select 
   Id, 
   [Date], 
   [Value]
from cte
where 
    (tot >= 30 and [Value] = 0)
    or tot > 30

【讨论】:

  • 您的查询将忽略 4 | 2018-01-04 | 0 :) 这一行
  • 谢谢scsimon!像魅力一样工作:)
【解决方案2】:

您可以尝试在子查询中使用SUM 和窗口函数 来累积totle 然后在主查询中写入条件。

select Id,
      Date,
      Value
from 
(
  SELECT *,
         SUM(Value) OVER(ORDER BY Date) totle
  FROM thresholdTest
) t
WHERE totle > 30 OR (Value = 0 AND totle = 30)

[结果]

| Id |       Date | Value |
|----|------------|-------|
|  4 | 2018-01-04 |     0 |
|  5 | 2018-01-05 |     5 |
|  6 | 2018-01-06 |    10 |
|  7 | 2018-01-07 |     5 |
|  8 | 2018-01-08 |     0 |
|  9 | 2018-01-09 |     0 |
| 10 | 2018-01-10 |    10 |

sqlfiddle

【讨论】:

    【解决方案3】:

    另一种方法

    select t1.id, t1.Date,t1.Value
    from [thresholdTest] t1
    inner join [thresholdTest] t2 on t1.id >= t2.id
    group by t1.id, t1.value, t1.Date
    HAVING SUM(t2.VAlue)>30 OR( SUM(t2.value)=30 AND t1.value=0)
    

    【讨论】:

      猜你喜欢
      • 2020-07-11
      • 2016-06-18
      • 2017-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-08
      • 1970-01-01
      相关资源
      最近更新 更多