确定列是增加还是减少

时间:2021-06-08 03:35:46

标签: sql sql-server tsql sql-server-2014

我有一个数据表,其中列 ORDER 应该指示值是增加还是减少,另一列 ORDER_BASIS。但是,ORDER 中的数据通常一开始就不正确,因此我尝试使用 ORDER_BASIS 确定正确的顺序。

这是表格的样子:

<头>
ORDER ORDER_BASIS
增加 8
增加 16
增加 12
增加 5
增加 1
增加 1
增加 10
增加 16
增加 16

我正在努力实现这一目标:

<头>
ORDER ORDER_BASIS CORRECT_ORDER
增加 8 增加
增加 16 增加
增加 12 递减
增加 5 递减
增加 1 递减
增加 1 递减
增加 10 增加
增加 16 增加
增加 16 增加

第一列可以使用 ORDER 然后接下来的行应该确定它是增加还是减少。如果值没有增加或减少,则保持其当前状态,直到值发生变化。

我当前的逻辑使用 LAG 和 LEAD:

SELECT
    LEAD (ORDER_BASIS, 1, 0) AS NEXT_BASIS,
    LAG (ORDER_BASIS, 1, 0) AS PREV_BASIS
FROM 
    DATA_TABLE

然后创建了一个条件,但无法使其正常工作

CASE 
    WHEN CAST(PREV_BASIS AS int) = 0  
         OR (CAST(PREV_BASIS AS int) >= CAST(ORDER_BASIS AS int) 
             AND CAST(NEXT_BASIS AS int) <= CAST(ORDER_BASIS AS int))   
        THEN ORDER_BASIS 
        ELSE 'OPPOSITE_DIRECTION' 
END AS CORRECT_ORDER

使用 SQL Server 2014

2 个答案:

答案 0 :(得分:1)

如果您的查询没有任何 order by 语句,则行的顺序在任何时候都是完全随机的,并且可以不同。所以要解决这个问题,你需要一些可以保证行的初始顺序的列,然后我们可以解决这个问题:

select * , 
 case when ORDER_BASIS > LAG(ORDER_BASIS,1,-1) over (order by <the column>) 
    then 'INCREASING'
 case when ORDER_BASIS = LAG(ORDER_BASIS,1,-1) over (order by <the column>) 
   then 'No change'
 else 'DECREASING' end CORRECT_ORDER
from DATA_TABLE

答案 1 :(得分:0)

对于顺序处理函数,例如 LAGLEAD,顺序是最重要的维护因素,并且是原始帖子中遗漏的一项。在 SQL Server 中,窗口函数将根据自己的分区(分组)和排序条件进行操作,因此在直观地关联数据时,在外部查询中使用与窗口函数相同的条件非常重要。

<块引用>

可以在这个小提琴中探索以下解决方案:http://sqlfiddle.com/#!18/5e1ee/31

要验证您的输入条件,请运行查询以输出 LAGLEAD 结果:

SELECT
  [Id],[Order]
  , LAG (ORDER_BASIS, 1, NULL) OVER (ORDER BY [Id]) AS PREV_BASIS
  , [Order_Basis]
  , LEAD (ORDER_BASIS, 1, NULL) OVER (ORDER BY [Id]) AS NEXT_BASIS
FROM DATA_TABLE;
<头>
ID 订单 PREV_BASIS Order_Basis NEXT_BASIS
1 增加 (空) 8 16
2 增加 8 16 12
3 增加 16 12 5
4 增加 12 5 1
5 增加 5 1 1
6 增加 1 1 10
7 增加 1 10 16
8 增加 10 16 16
9 增加 16 16 (空)

下一个问题是您尝试的逻辑正在使用 LAG AND LEAD 值,这不是无效的,但通常用于计算一个值平滑曲线或试图检测峰值高点低点

<块引用>

没有必要通过 CTE 执行此操作,但是,它简化了本讨论的语法的可读性,在 CTE 中我们也可以执行整数转换,但是在生产环境中,最好存储ORDER_BASIS 列首先作为整数。

WITH Records as
(
  SELECT
    [Id],[Order]
    , CAST(LAG (ORDER_BASIS, 1, NULL) OVER (ORDER BY [Id]) AS INT) AS PREV_BASIS
    , CAST([Order_Basis] AS INT) AS [Order_Basis]
    , CAST(LEAD (ORDER_BASIS, 1, NULL) OVER (ORDER BY [Id]) AS INT) AS NEXT_BASIS
  FROM DATA_TABLE
)
SELECT
    [Id],[Order],PREV_BASIS,[Order_Basis],NEXT_BASIS
    ,CASE 
        WHEN NEXT_BASIS > ORDER_BASIS AND PREV_BASIS > ORDER_BASIS THEN 'LOW'
        WHEN NEXT_BASIS < ORDER_BASIS AND PREV_BASIS < ORDER_BASIS THEN 'HIGH'
        WHEN ISNULL(PREV_BASIS, ORDER_BASIS) = ORDER_BASIS THEN 'NO CHANGE'
        WHEN ISNULL(PREV_BASIS, ORDER_BASIS) >= ORDER_BASIS 
               AND ISNULL(NEXT_BASIS, ORDER_BASIS) <= ORDER_BASIS
          THEN 'DECREASING' 
        WHEN ISNULL(PREV_BASIS, ORDER_BASIS) <= ORDER_BASIS 
               AND ISNULL(NEXT_BASIS, ORDER_BASIS) >= ORDER_BASIS 
        THEN 'INCREASING' 
        ELSE 'INDETERMINATE'
    END AS CORRECT_ORDER
FROM Records
ORDER BY [Id];
<头>
ID 订单 PREV_BASIS Order_Basis NEXT_BASIS CORRECT_ORDER
1 增加 (空) 8 16 没有变化
2 增加 8 16 12
3 增加 16 12 5 递减
4 增加 12 5 1 递减
5 增加 5 1 1 递减
6 增加 1 1 10 没有变化
7 增加 1 10 16 增加
8 增加 10 16 16 增加
9 增加 16 16 (空) 没有变化

您可以再次使用 LAG 比较来扩展这一点,以确定上述记录集中间的 NO CHANGE 是否实际上是更长时期内的低点。

如果 CORRECT ORDER 应该只是前一条记录的函数,那么根本不需要使用 LEAD 评估:

WITH Records as
(
  SELECT
    [ID],[ORDER]
    , CAST(LAG (ORDER_BASIS, 1, NULL) OVER (ORDER BY [Id]) AS INT) AS PREV_BASIS
    , CAST([ORDER_BASIS] AS INT) AS [ORDER_BASIS]
  FROM DATA_TABLE
)
SELECT 
  [ID],[ORDER],[PREV_BASIS],[ORDER_BASIS]
  , CASE WHEN ORDER_BASIS < PREV_BASIS
           THEN 'DECREASING'
         WHEN ORDER_BASIS > PREV_BASIS
          THEN 'INCREASING'
         ELSE 'NO CHANGE' 
    END CORRECT_ORDER
FROM Records;
<头>
ID 订单 PREV_BASIS ORDER_BASIS CORRECT_ORDER
1 增加 (空) 8 没有变化
2 增加 8 16 增加
3 增加 16 12 递减
4 增加 12 5 递减
5 增加 5 1 递减
6 增加 1 1 没有变化
7 增加 1 10 增加
8 增加 10 16 增加
9 增加 16 16 没有变化