【问题标题】:SQL need to apply a variable rate if values occur over consecutive time periods如果值在连续时间段内出现,SQL 需要应用可变速率
【发布时间】:2016-01-13 18:10:51
【问题描述】:

我有一张如下所示的表格:

在查询中,我需要找到两个时间段(行)内出现的最大导入值,其中该值大于定义的阈值并应用速率。如果它发生在两个以上的时间段内,将使用不同的速率

Threshold = 1000 
Rate 1 (2 consecutive) = 100
Rate 2 (> 2 consecutive) = 200

Id    DateTime            Import       Export Total
1     2016-01-13 00:00    1000         500    1500
2     2016-01-13 00:15    2500         100    3000
3     2016-01-13 00:30    1900         200    2100
4     2016-01-13 01:00    900          100    1200

ID 2 和 3 是 > 阈值,因此查询应返回那些 (2500,1900) = 1900 减去阈值 (1000) = 900 的最小值。应用速率 Rate1 * 900 = 9000

如果我们将 Id 4 的值更改为 1200,那么 MIN 值将是 1200。减去阈值 = 200。200 * Rate2 = 4000

任何帮助将不胜感激!

反馈后更新。我的挑战似乎是我没有获得第二高的价值。以下是数据集的示例: Dataset example

我添加了另一个变量来缩小列表以测试间隙和孤岛部分。这是一个较小的子集: Subset

代码如下:

    WITH CTE AS (  

SELECT LogTable.[LocalTimestamp] as thetime,LogTable.[SystemImport] as import, LogTable.[Id] - ROW_NUMBER() OVER (ORDER BY LogTable.[Id]) AS grp
  FROM {System_KWLogRaw} LogTable
  WHERE LogTable.[SystemImport] between @DemandThreshold and @In1 and 
    DATEPART(year,@inDate) = DATEPART(year, LogTable.[LocalTimestamp]) and
    DATEPART(month,@inDate) = DATEPART(month, LogTable.[LocalTimestamp]) and
    DATEPART(day,@inDate) = DATEPART(day, LogTable.[LocalTimestamp])
),

counted AS (
    SELECT *, COUNT(*) OVER (PARTITION BY grp) AS cnt
    FROM CTE

    )

SELECT MAX(counted.import) as again1
FROM counted
WHERE cnt > 3 and counted.import < (SELECT MAX(counted.import) FROM counted)

这将返回 3555.53 而不是 3543.2,后者是第二高的值

【问题讨论】:

  • 您的样本数据会得到什么结果?我假设 9000 和 4000 不是您正在寻找的完整结果集。另外,您使用的是什么 RDBMS?语法因服务器而异。
  • 嗨兔子!我正在使用 SQL 2012。在这种情况下,结果将是一个值(9000 或 4000),具体取决于连续记录的数量是 = 2 (rate_1) 还是大于 2 (rate_2)。我的例子是误导它出现。想象一下数据集相当大 - 如果使用我原来的逻辑,我会错过答案。需要的是前 2 个值的 MIN(在连续 = 2 的情况下)或前 X 值(在连续> 2 的情况下。这有意义吗?
  • 我在问题中添加了 RDBMS。但是您的其余评论是对您问题的重复。听起来您想运行一个查询,而查询返回的唯一内容是一个数字。但这对我来说听起来不是很有用。根本没有任何支持信息。假设您有一百万条记录。你想运行一个查询,查询的结果是 50000。这真的是你想要的吗?
  • 另外,您上面的结果不正确。 900 * Rate1(100) = 90000,而不是 9000。第二个结果相同。
  • 如果您真正想要的只是一个数字结果。并假设您的 id 是严格连续的,就像您的示例数据显示的那样。然后,您可以使用岛和间隙查询结合窗口函数来做您想做的事情。

标签: sql sql-server-2012 common-table-expression


【解决方案1】:

这将满足您的要求:

with x as (
select
t1.Id,
t1.DateTime,
t1.Import,
t1.Export,
t1.Total,
count(t2.Import) over (partition by 1) as [QualifyingImports],
min(t2.Import) over (partition by 1) as [MinQualifyingImport]

from
myTable t1
left join myTable t2 on t2.Import > 1000 and t2.Id = t1.Id

where
t1.DateTime >= '2016-01-13'
and t1.DateTime < dateadd(d, 1,'2016-01-13')

)

select
x.Id,
x.DateTime,
x.Import,
x.Export,
x.Total,
case when x.[QualifyingImports] > 2 then (x.MinQualifyingImport - 1000) * 200 else (x.MinQualifyingImport - 1000) * 100 end as [Rate]
from x

我已将Fiddle 放在一起,因此您可以使用 Id #4 的不同值。

我真的很想把阈值和周期之类的值变成@variables,但它似乎在 CTE 中不受支持,所以我只好硬编码它们。

编辑

原来 CTE 是多余的,你可以把它缩小到这个并使用 @variables,耶!

declare @period smalldatetime = '2016-01-13'
declare @threshold float = 1000
declare @rate1 float = 100
declare @rate2 float = 200

select
t1.Id,
t1.DateTime,
t1.Import,
t1.Export,
t1.Total,
case
  when count(t2.Import) over (partition by 1) > 2 then (min(t2.Import) over (partition by 1) - @threshold) * @rate2
  else (min(t2.Import) over (partition by 1) - @threshold) * @rate1
  end as [Rate]

from
myTable t1
left join myTable t2 on t2.Import > @threshold and t2.Id = t1.Id

where
t1.DateTime >= @period
and t1.DateTime < dateadd(d, 1, @period)

新Fiddle

【讨论】:

  • 嗨乔!感谢您的帮助!恐怕当我输入一个新值来测试连续部分时,它的逻辑会失败:sqlfiddle.com/#!3/8111e/2 这个要求背后的目的是允许数据快速起伏,只要它们不跨越某个连续时间段数。
  • “Id”中的值是否随着日期时间的递增而递增?如果是这样,我们可以使用它来模拟带有另一个自连接的 LEAD / LAG 函数。
  • 不确定this 是否适合您?它现在检查前一行以查看该行是否也具有高于阈值的 Import 值,并且仅在这种情况下应用 rate2(即超过阈值的导入必须是连续的)。这会导致“费率”列中的值发生变化,因此可能不完全符合您的需要,但我们是否正在接近?
  • 嗨乔!再次感谢!!我在更新中发布的代码似乎可以找到正确的值。缺少的一件事是,我必须在查询之外应用它,而不是在此处应用速率,因此查询需要输出一个值(最好是布尔值),如果 cnt > 4 则为 True 这样我就会知道要应用什么速率道路
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
  • 1970-01-01
  • 2013-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多