Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何使用SQL Server 2012计算峰谷水位下降?_Sql Server_Tsql_Sql Server 2012 - Fatal编程技术网

Sql server 如何使用SQL Server 2012计算峰谷水位下降?

Sql server 如何使用SQL Server 2012计算峰谷水位下降?,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,我想知道一些新的SQL Server 2012函数是否有助于解决此问题。这是我的DDL和示例数据 CREATE TABLE [dbo].[transactions] ( [transactionId] [int] NOT NULL, [dt] [datetime] NOT NULL, [balance] [decimal](22, 6) NULL ); GO INSERT [dbo].[tran

我想知道一些新的SQL Server 2012函数是否有助于解决此问题。这是我的DDL和示例数据

CREATE TABLE [dbo].[transactions]
(
    [transactionId] [int]            NOT NULL,
    [dt]            [datetime]       NOT NULL,
    [balance]       [decimal](22, 6) NULL
);    
GO

INSERT [dbo].[transactions] ([transactionId], [dt], [balance]) VALUES
 (174, CAST(0x0000A19600000000 AS DateTime), CAST(1000.000000 AS Decimal(22, 6))), 
 (178, CAST(0x0000A19700869520 AS DateTime), CAST(1100.000000 AS Decimal(22, 6))),
 (179, CAST(0x0000A19700933780 AS DateTime), CAST(1212.000000 AS Decimal(22, 6))),
 (180, CAST(0x0000A19700B4B9A0 AS DateTime), CAST(1342.000000 AS Decimal(22, 6))),
 (181, CAST(0x0000A19700BB0AD0 AS DateTime), CAST(1198.000000 AS Decimal(22, 6))),
 (182, CAST(0x0000A19700E67030 AS DateTime), CAST(1234.000000 AS Decimal(22, 6))),
 (183, CAST(0x0000A19700F358E0 AS DateTime), CAST(900.000000  AS Decimal(22, 6))),
 (184, CAST(0x0000A19700F58B60 AS DateTime), CAST(876.000000  AS Decimal(22, 6))),
 (185, CAST(0x0000A19700F9AA10 AS DateTime), CAST(889.000000  AS Decimal(22, 6))),
 (186, CAST(0x0000A19701034700 AS DateTime), CAST(1133.000000 AS Decimal(22, 6))),
 (187, CAST(0x0000A19A0089E0E0 AS DateTime), CAST(1400.000000 AS Decimal(22, 6))),
 (191, CAST(0x0000A19A009450C0 AS DateTime), CAST(1566.000000 AS Decimal(22, 6))),
 (192, CAST(0x0000A19A00A5E4C0 AS DateTime), CAST(1800.000000 AS Decimal(22, 6))),
 (188, CAST(0x0000A19A00AA49C0 AS DateTime), CAST(1900.000000 AS Decimal(22, 6))),
 (189, CAST(0x0000A19A00B54640 AS DateTime), CAST(1456.000000 AS Decimal(22, 6))),
 (190, CAST(0x0000A19A00CAB2A0 AS DateTime), CAST(1234.000000 AS Decimal(22, 6))),
 (193, CAST(0x0000A19A00F12660 AS DateTime), CAST(1400.000000 AS Decimal(22, 6))),
 (195, CAST(0x0000A19A010087E0 AS DateTime), CAST(1444.000000 AS Decimal(22, 6))),
 (196, CAST(0x0000A19E00C7F380 AS DateTime), CAST(1556.000000 AS Decimal(22, 6))),
 (197, CAST(0x0000A19E00FE5560 AS DateTime), CAST(1975.000000 AS Decimal(22, 6)));
我在寻找dt订购的该系列余额的最大百分比峰谷下降。峰谷水位降是平衡中的一个高点到上一个高点之前的最低低点的最大百分比变化。在这个数据集中,我们有两个提取

第一个是从1342.00到876.00(-34.72%),第二个是从1900到1234(-35.05%)


因此,该组中最大峰谷百分比下降为-35.05%。我需要一个可以提供此值的SQL Server查询。如果可能的话,我们宁愿不使用临时表。有什么想法吗?

我不知道任何SQL Server 2012功能会比这个更简洁、更有效地获得这个值:

;WITH x AS
(
  SELECT [drop] = ((s.balance-e.balance)*100.0/s.balance)
    FROM dbo.transactions AS s
    INNER JOIN dbo.transactions AS e
    ON s.transactionId < e.transactionId
    AND s.balance > e.balance
)
SELECT [Largest Drawdown] = -MAX([drop]) FROM x;
不过,我承认,这只适用于您的示例数据,因为您的山谷对于您想要解决的问题很方便。如果将最后第四行更改为875,则此查询将认为是集合的一部分。换句话说,我在这里计算了整个范围的下降,而不仅仅是在再次越过高点之前的范围


我怀疑有一种更好的方法可以使用gap/island技术来解决这个查询,当我能够充分关注它时,我会尝试返回到它。

如果第一个条目是峰值,这将错过

 ;with trnsCTE (ID,bal) AS
  (  -- get seqential ID
        SELECT ROW_NUMBER() OVER (ORDER BY DT) as ID, [balance] 
        from [transactions] 
  ),
  trnsCTE2 (ID,bal) AS
  ( -- any peaks
       select t2.ID, t2.bal 
       from  trnsCTE as T1
       join  trnsCTE as T2
         on  ( t2.ID = t1.ID+1  
        and  t2.bal > t1.bal )
       join  trnsCTE as T3
         on  t3.ID = t2.ID+1
        and  t3.bal < t1.bal
   )
   ,
   trnsCTE3 (ID,bal) AS
   (  --  get first peak and then bigger peaks only
       SELECT distinct T1.ID, T1.BAL
       from  trnsCTE2 as T1
       where T1.ID = (select min(ID) from trnsCTE2) 
         or T1.bal > (select max(bal) from trnsCTE2 where trnsCTE2.ID < t1.ID)
   )
   -- calculate 
   select t1.id, t1.bal, min(trnsCTE.bal), (t1.bal - min(trnsCTE.bal)) * 100 / t1.bal
   from trnsCTE
   join trnsCTE3 t1
     on t1.id < trnsCTE.id 
    and ( trnsCTE.id < (select min(id) from trnsCTE3 where id > t1.id)
          or
          t1.id = ( select max(id) from trnsCTE3 ) )
   group by t1.id, t1.bal 
   order by t1.id

@AaronBertrand谢谢你的编辑是的,在一系列的“高峰”之后,我需要最大的百分比下降。这给了我想要的,但表现很差。也许我需要一个临时表解决方案?你的问题是“宁愿不使用临时表”。使用该约束纠正结果,甚至不使用+1的礼貌。无意冒犯。在只有几百行的数据集上,查询运行时间超过30秒。我只是想知道是否有一种优雅高效的方法可以在一条T-SQL语句中实现这一点。
 ;with trnsCTE (ID,bal) AS
  (  -- get seqential ID
        SELECT ROW_NUMBER() OVER (ORDER BY DT) as ID, [balance] 
        from [transactions] 
  ),
  trnsCTE2 (ID,bal) AS
  ( -- any peaks
       select t2.ID, t2.bal 
       from  trnsCTE as T1
       join  trnsCTE as T2
         on  ( t2.ID = t1.ID+1  
        and  t2.bal > t1.bal )
       join  trnsCTE as T3
         on  t3.ID = t2.ID+1
        and  t3.bal < t1.bal
   )
   ,
   trnsCTE3 (ID,bal) AS
   (  --  get first peak and then bigger peaks only
       SELECT distinct T1.ID, T1.BAL
       from  trnsCTE2 as T1
       where T1.ID = (select min(ID) from trnsCTE2) 
         or T1.bal > (select max(bal) from trnsCTE2 where trnsCTE2.ID < t1.ID)
   )
   -- calculate 
   select t1.id, t1.bal, min(trnsCTE.bal), (t1.bal - min(trnsCTE.bal)) * 100 / t1.bal
   from trnsCTE
   join trnsCTE3 t1
     on t1.id < trnsCTE.id 
    and ( trnsCTE.id < (select min(id) from trnsCTE3 where id > t1.id)
          or
          t1.id = ( select max(id) from trnsCTE3 ) )
   group by t1.id, t1.bal 
   order by t1.id
insert into #trnsCTE (ID,bal)
SELECT ROW_NUMBER() OVER (ORDER BY DT) as ID, [balance] 
from [transactions]
select peak_dt, peak_balance, trough_dt, trough_balance, (peak_balance - trough_balance) * 100.0 / peak_balance as drawdown
from (
    select dt as peak_dt, balance as peak_balance, nullif(last_value(dt) over (partition by peak_valley_group order by dt rows between unbounded preceding and unbounded following), dt) as trough_dt, nullif(last_value(balance) over (partition by peak_valley_group order by dt rows between unbounded preceding and unbounded following), balance) as trough_balance, isPeak
    from (
        select *, sum(isPeak) over (order by dt) as peak_valley_group
        from (
            select dt, balance, (case when forward_trend = -1 then 1 else 0 end) as isPeak, max(balance) over (partition by forward_trend order by dt) as current_max_balance
            from (
                -- Nulls for lead/lag here produce the desired result
                select *, (case when lead(balance, 1) over (order by dt) > balance then 1 else -1 end) as forward_trend, (case when lag(balance, 1) over (order by dt) > balance then 1 else -1 end) as backward_trend
                from transactions
            ) t
            where forward_trend = backward_trend
        ) t
        where (isPeak = 1 and balance = current_max_balance) 
        or isPeak = 0
    ) t
) t
where isPeak = 1
order by peak_dt