在“有效”期间

时间:2017-10-26 15:57:00

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

我很难写好标题,所以我会在这里详细描述这个问题。

我们有表[dbo]。[LEASE_APPLICATIONS_AUDIT_LOG],用于存储更改日期时间的历史数据。如果数据的状态不是IN('E','F','I','O','X')那么这意味着它在那时被批准,如果状态不是这些那些,然后它没有被批准。它可以被批准,也不会以任何顺序和多次批准。例如:

'2010.01.01', 'A'
'2010.02.01', 'B'
'2010.03.01', 'E'
'2010.04.01', 'Z'

这意味着该记录从2010.01.01至2010.03.01获得批准,然后在2010.04.01再次获得批准。

还有另一个表[dbo]。[LEASE_FINANCING_AUDIT_LOG],用于存储当时的基本付款金额。例如,如果对于相同的记录,我会有这样的条目:

'2010.01.01', 123
'2010.04.01', 321

那么这意味着从2010.01.01到2010.03.01(未经批准)从基本付款是123,然后从2010.04.01起,价值变为321。

可能存在各种状态更改组合,并且在任何时间段都可能存在不同的基本支付值。

因此,目标是找到介于APPROVED期间的最新base_payment值。

以下是我们迄今为止制作的脚本。有2个表格,包含该数据和功能。其他代码片段来自单元测试,这就是为什么它们是这样的,如果逻辑不是预期的那样,它们将输出'bad'字符串。该功能正在运行,但我不太喜欢TOP 1 / ORDER BY方法,并试图找出是否有更好的方法来实现这一点。有什么想法吗?

SET NOCOUNT ON;

CREATE TABLE [dbo].[LEASE_APPLICATIONS_AUDIT_LOG]
(
    [LEASE_APPLICATION]       CHAR(8)
  , [APPLICATION_STATUS_CODE] CHAR(1)
  , [CHANGED_DATE]            DATETIME2(7) NOT NULL
);
GO

CREATE TABLE [dbo].[LEASE_FINANCING_AUDIT_LOG]
(
    [LEASE_APPLICATION] CHAR(8)
  , [BASE_PAYMENT]      DECIMAL(10, 2) NULL
  , [CHANGED_DATE]      DATETIME2(7)   NOT NULL
);
GO

CREATE FUNCTION [dbo].[post_approval_payment_amount] (@lease_application CHAR(8))
RETURNS TABLE
AS
RETURN (
           SELECT TOP 1 lfal.BASE_PAYMENT AS post_approval_payment_amount
             FROM LEASE_APPLICATIONS_AUDIT_LOG laal
            CROSS APPLY
                (
                    SELECT TOP 1 lf.BASE_PAYMENT
                      FROM LEASE_FINANCING_AUDIT_LOG lf
                     WHERE lf.LEASE_APPLICATION = laal.LEASE_APPLICATION
                       AND lf.CHANGED_DATE      < COALESCE((
                                                               SELECT TOP 1 la.CHANGED_DATE
                                                                 FROM LEASE_APPLICATIONS_AUDIT_LOG la
                                                                WHERE la.LEASE_APPLICATION = laal.LEASE_APPLICATION
                                                                  AND la.CHANGED_DATE      > laal.CHANGED_DATE
                                                                ORDER BY la.CHANGED_DATE
                                                           ), CAST('9999-12-31 23:59:59' AS DATETIME))
                     ORDER BY lf.CHANGED_DATE DESC
                )                              lfal
            WHERE laal.LEASE_APPLICATION = @lease_application
              AND laal.APPLICATION_STATUS_CODE NOT IN ('E', 'F', 'I', 'O', 'X')
            ORDER BY laal.CHANGED_DATE DESC
       );
GO

DECLARE @lease_application CHAR(8) = '35163328'
      , @base_payment      DECIMAL = 209.12
      , @expected          DECIMAL = 209.12
      , @actual            DECIMAL;

DECLARE @la AS TABLE
(
    change_date             DATETIME2(7)
  , application_status_code CHAR(1)     NULL
  , base_amount             DECIMAL     NULL
  , is_laal                 BIT
);

INSERT INTO @la (   change_date
                  , application_status_code
                  , base_amount
                  , is_laal
                )
VALUES ('2017-05-11 03:46:26.4800000', 'K', NULL, 1)
     , ('2017-05-11 03:48:05.0600000', NULL, @base_payment, 0)
     , ('2017-06-21 14:07:51.2200000', 'X', NULL, 1);

INSERT INTO dbo.lease_applications_audit_log (   LEASE_APPLICATION
                                               , CHANGED_DATE
                                               , APPLICATION_STATUS_CODE
                                             )
SELECT @lease_application
     , l.change_date
     , l.application_status_code
  FROM @la AS l
 WHERE l.is_laal = 1;

INSERT INTO dbo.lease_financing_audit_log (   LEASE_APPLICATION
                                            , CHANGED_DATE
                                            , BASE_PAYMENT
                                          )
SELECT @lease_application
     , l.change_date
     , l.base_amount
  FROM @la AS l
 WHERE l.is_laal = 0;

SELECT @actual = post_approval_payment_amount
  FROM [dbo].[post_approval_payment_amount](@lease_application);

IF (@expected <> @actual) SELECT 'Test 1 failed'
ELSE SELECT 'Test 1 passed';


SELECT @lease_application = '30000152'
     , @base_payment      = 622.15
     , @expected          = 622.15;

DELETE FROM @la;

INSERT INTO @la (   change_date
                  , application_status_code
                  , base_amount
                  , is_laal
                )
VALUES ('2017-05-11 03:46:26.4800000', 'z', NULL, 1)
     , ('2017-05-11 03:48:05.0600000', NULL, @base_payment, 0);

INSERT INTO dbo.lease_applications_audit_log (   LEASE_APPLICATION
                                               , CHANGED_DATE
                                               , APPLICATION_STATUS_CODE
                                             )
SELECT @lease_application
     , l.change_date
     , l.application_status_code
  FROM @la AS l
 WHERE l.is_laal = 1;

INSERT INTO dbo.lease_financing_audit_log (   LEASE_APPLICATION
                                            , CHANGED_DATE
                                            , BASE_PAYMENT
                                          )
SELECT @lease_application
     , l.change_date
     , l.base_amount
  FROM @la AS l
 WHERE l.is_laal = 0;

SELECT @actual = post_approval_payment_amount
  FROM [dbo].[post_approval_payment_amount](@lease_application);

IF (@expected <> @actual) SELECT 'Test 2 failed'
ELSE SELECT 'Test 2 passed';

SELECT @lease_application = '38768578'
     , @base_payment      = 453.70
     , @expected          = NULL
     , @actual            = NULL;

DELETE FROM @la;

INSERT INTO @la (   change_date
                  , application_status_code
                  , base_amount
                  , is_laal
                )
VALUES ('2017-05-11 03:46:26.4800000', 'L', NULL, 1)
     , ('2017-06-09 12:00:36.2000000', 'X', NULL, 1)
     , ('2017-06-12 03:48:05.0600000', NULL, @base_payment, 0);

INSERT INTO dbo.lease_applications_audit_log (   LEASE_APPLICATION
                                               , CHANGED_DATE
                                               , APPLICATION_STATUS_CODE
                                             )
SELECT @lease_application
     , l.change_date
     , l.application_status_code
  FROM @la AS l
 WHERE l.is_laal = 1;

INSERT INTO dbo.lease_financing_audit_log (   LEASE_APPLICATION
                                            , CHANGED_DATE
                                            , BASE_PAYMENT
                                          )
SELECT @lease_application
     , l.change_date
     , l.base_amount
  FROM @la AS l
 WHERE l.is_laal = 0;

SELECT @actual = post_approval_payment_amount
  FROM [dbo].[post_approval_payment_amount](@lease_application);

IF (@actual IS NOT NULL) SELECT 'Test 3 failed'
ELSE SELECT 'Test 3 passed';

SELECT @lease_application = '38282661'
     , @base_payment      = 451.25
     , @expected          = 451.25;

DELETE FROM @la;

INSERT INTO @la (   change_date
                  , application_status_code
                  , base_amount
                  , is_laal
                )
VALUES ('2017-05-11 03:46:26.4800000', 'O', NULL, 1)
     , ('2017-05-11 03:48:05.0600000', NULL, @base_payment, 0)
     , ('2017-07-05 10:52:14.6800000', 'O', NULL, 1)
     , ('2017-07-05 11:10:24.0400000', 'E', NULL, 1)
     , ('2017-07-05 11:10:25.6000000', 'E', NULL, 1)
     , ('2017-07-05 11:10:49.1900000', 'L', NULL, 1)
     , ('2017-07-06 00:04:30.6400000', 'O', NULL, 1);

INSERT INTO dbo.lease_applications_audit_log (   LEASE_APPLICATION
                                               , CHANGED_DATE
                                               , APPLICATION_STATUS_CODE
                                             )
SELECT @lease_application
     , l.change_date
     , l.application_status_code
  FROM @la AS l
 WHERE l.is_laal = 1;

INSERT INTO dbo.lease_financing_audit_log (   LEASE_APPLICATION
                                            , CHANGED_DATE
                                            , BASE_PAYMENT
                                          )
SELECT @lease_application
     , l.change_date
     , l.base_amount
  FROM @la AS l
 WHERE l.is_laal = 0;

SELECT @actual = post_approval_payment_amount
  FROM [dbo].[post_approval_payment_amount](@lease_application);

IF (@expected <> @actual) SELECT 'Test 4 failed'
ELSE SELECT 'Test 4 passed';

SELECT @lease_application = '38768578'
     , @base_payment      = 453.70
     , @expected          = 453.70;

DELETE FROM @la;

INSERT INTO @la (   change_date
                  , application_status_code
                  , base_amount
                  , is_laal
                )
VALUES ('2017-05-11 03:46:26.4800000', 'L', NULL, 1)
     , ('2017-05-11 03:48:05.0600000', NULL, 200, 0)
     , ('2017-05-12 03:48:05.0600000', NULL, @base_payment, 0)
     , ('2017-06-09 12:00:36.2000000', 'X', NULL, 1)
     , ('2017-09-18 11:57:13.5100000', NULL, 100, 0);

INSERT INTO dbo.lease_applications_audit_log (   LEASE_APPLICATION
                                               , CHANGED_DATE
                                               , APPLICATION_STATUS_CODE
                                             )
SELECT @lease_application
     , l.change_date
     , l.application_status_code
  FROM @la AS l
 WHERE l.is_laal = 1;

INSERT INTO dbo.lease_financing_audit_log (   LEASE_APPLICATION
                                            , CHANGED_DATE
                                            , BASE_PAYMENT
                                          )
SELECT @lease_application
     , l.change_date
     , l.base_amount
  FROM @la AS l
 WHERE l.is_laal = 0;

SELECT @actual = post_approval_payment_amount
  FROM [dbo].[post_approval_payment_amount](@lease_application);

IF (@expected <> @actual) SELECT 'Test 5 failed'
ELSE SELECT 'Test 5 passed';

SELECT @lease_application = '38768578'
     , @base_payment      = 453.70
     , @expected          = 453.70;

DELETE FROM @la;

INSERT INTO @la (   change_date
                  , application_status_code
                  , base_amount
                  , is_laal
                )
VALUES ('2017-05-11 03:46:26.4800000', 'L', NULL, 1)
     , ('2017-05-11 03:48:05.0600000', NULL, @base_payment, 0)
     , ('2017-06-09 12:00:36.2000000', 'X', NULL, 1)
     , ('2017-09-18 11:57:13.5100000', NULL, 100, 0);

INSERT INTO dbo.lease_applications_audit_log (   LEASE_APPLICATION
                                               , CHANGED_DATE
                                               , APPLICATION_STATUS_CODE
                                             )
SELECT @lease_application
     , l.change_date
     , l.application_status_code
  FROM @la AS l
 WHERE l.is_laal = 1;

INSERT INTO dbo.lease_financing_audit_log (   LEASE_APPLICATION
                                            , CHANGED_DATE
                                            , BASE_PAYMENT
                                          )
SELECT @lease_application
     , l.change_date
     , l.base_amount
  FROM @la AS l
 WHERE l.is_laal = 0;

SELECT @actual = post_approval_payment_amount
  FROM [dbo].[post_approval_payment_amount](@lease_application);

IF (@expected <> @actual) SELECT 'Test 6 failed'
ELSE SELECT 'Test 6 passed';

DROP TABLE [dbo].[LEASE_APPLICATIONS_AUDIT_LOG];
GO

DROP TABLE [dbo].[LEASE_FINANCING_AUDIT_LOG];
GO

DROP FUNCTION [dbo].[post_approval_payment_amount];
GO

1 个答案:

答案 0 :(得分:0)

你问了一些关于替代方法的想法。您可以单独或组合使用这些想法:

  1. 请记住,JOIN可以使用运算符其他而不是等号来完成,因此您可以加入表格ON LEASE_APPLICATIONS_AUDIT_LOG.CHANGED_DATE <= LEASE_FINANCING_AUDIT_LOG.CHANGED_DATE
  2. LAG和LEAD功能是检索&#34;附近&#34;的最佳功能。记录。第三个参数甚至允许您指定在找不到记录时将返回的值 - 这是插入CAST('9999-12-31 23:59:59' AS DATETIME默认值的便利位置。
  3. 永远不要低估通过正确使用公用表表达式(使用WITH子句)可以实现的清晰度和性能。