在sql中创建一个减法矩阵

时间:2017-10-23 08:05:52

标签: sql-server function sql-server-2012

我有一张这样的表:

id_nbr t1 t2 t3 t4 t5 t6
  1111  10 20 30 40 50 40  
  2222  40 10 50 20 70 90  

我想建立一个函数,每个id_nbr将返回最大减法和该减法的时间差异 - 例如:

对于id_nbr 1111,从t1到t5的最大值为40,因此该函数将在不同的单元格中返回40和4(5-1)。 对于id_nbr 2222,从t2到t5的最大值为60,因此函数将在diffrennt单元格中返回60和3(5-2)。

Output:
exec find_max_and_time (1111) 

max_diff time
  40      4

创建此类功能的任何帮助?

查询中建议的功能:

2 个答案:

答案 0 :(得分:0)

这里有一个可能的解决方案,通过unpivot。我们的想法是将您的六列变为行,将其rowindex表示为时间(根据您的示例),然后获取相应列的最小值和最大值。但是,您应该考虑处理重复项:可能会发生两个列具有相同的值,并且使用此列可以为最小值和最大值创建多个匹配记录。

DECLARE @t TABLE(
  id_nbr INT
 ,t1 INT
 ,t2 INT
 ,t3 INT
 ,t4 INT
 ,t5 INT
 ,t6 INT
);

INSERT INTO @t VALUES (1111,10,20,30,40,50,40), (2222,40,10,50,20,70,90);


DECLARE @SearchID INT = 2222;
DECLARE @TimeIdxFrom INT = 1;
DECLARE @TimeIdxTo INT = 5;

WITH cteBase AS(
  SELECT id_nbr, ROW_NUMBER() OVER (PARTITION BY id_nbr ORDER BY (SELECT 1)) rn, times
  FROM (
  SELECT id_nbr, t1, t2, t3, t4, t5, t6
    FROM @t t) t
    UNPIVOT(
      times FOR cTime IN (t1, t2, t3, t4, t5, t6)
    ) u
),
cteMinMax AS(
  SELECT id_nbr, MIN(times) MinTime, MAX(times) MaxTime
    FROM cteBase
    WHERE rn >= @TimeIdxFrom
      AND rn <= @TimeIdxTo
    GROUP BY id_nbr
)
SELECT  --*,
        cbMax.rn - cbMin.rn AS TimeSpan,
        cbMax.times - cbMin.times AS ValDiff
  FROM cteMinMax AS cmm
  JOIN cteBase AS cbMin ON cmm.id_nbr = cbMin.id_nbr AND cbMin.times = cmm.MinTime
  JOIN cteBase AS cbMax ON cmm.id_nbr = cbMax.id_nbr AND cbMax.times = cmm.MaxTime
  WHERE cbMax.id_nbr = @SearchID;

答案 1 :(得分:0)

NULL返回所有计算值

CREATE TABLE  dbo.T 
(
    id_nbr  INT,
    t1  INT,
    t2  INT,
    t3  INT,
    t4  INT,
    t5  INT,
    t6  INT
)
GO
INSERT INTO dbo.T   (id_nbr, t1, t2, t3, t4, t5, t6)
VALUES
(  1111,  10, 20, 30, 40, 50, 40  ),
(2222,  40, 10, 50, 20, 70, 90  )

GO

CREATE FUNCTION dbo.find_max_and_time(@Id INT)
RETURNS TABLE 
AS RETURN 
WITH Desce AS 
(
    SELECT TOP 1 WITH TIES a.id_nbr , b.*
    FROM dbo.T a
    CROSS APPLY 
    (
        SELECT 1, a.T1 UNION ALL
        SELECT 2, a.T2 UNION ALL
        SELECT 3, a.T3 UNION ALL
        SELECT 4, a.T4 UNION ALL
        SELECT 5, a.T5 UNION ALL
        SELECT 6, a.T6  
    ) as b(N,Val)
    WHERE id_nbr = @Id OR @Id IS NULL
    ORDER BY ROW_NUMBER() OVER(PARTITION BY id_nbr ORDER BY Val DESC)   
), Asce AS 
(
    SELECT TOP 1 WITH TIES a.id_nbr,b.*
    FROM dbo.T a
    CROSS APPLY 
    (
        SELECT 1, a.T1 UNION ALL
        SELECT 2, a.T2 UNION ALL
        SELECT 3, a.T3 UNION ALL
        SELECT 4, a.T4 UNION ALL
        SELECT 5, a.T5 UNION ALL
        SELECT 6, a.T6  
    ) as b(N,Val)   
    WHERE id_nbr = @Id OR @Id IS NULL
    ORDER BY ROW_NUMBER() OVER(PARTITION BY id_nbr ORDER BY Val ASC)    
)
SELECT 
    a.id_nbr, 
    a.Val - b.Val   as Val,
    a.N - b.N   as N
FROM 
    Desce a
INNER JOIN 
    Asce b
ON a.id_nbr = b.id_nbr

GO

SELECT * FROM dbo.find_max_and_time (1111)

DROP TABLE dbo.T 
DROP FUNCTION dbo.find_max_and_time