2017-10-26 16 views
0

の間で最新のお支払い値を見つけてください。いいタイトルを書くのはかなり難しいので、ここで詳しく説明します。"有効期間"

変更された日付時刻の履歴データを保存する[dbo]。[LEASE_APPLICATIONS_AUDIT_LOG]があります。データのステータスがINではない場合( 'E'、 'F'、 'I'、 'O'、 'X')、その時点で承認されたことを意味し、ステータスがこれら以外の場合それは承認されていません。それは承認され、いかなる順序でも何度も承認されないことがあります。たとえば、次の

レコードは2010年3月1日まで2010年1月1日から承認された後、2010年4月1日で再び承認されたことを意味し
'2010.01.01', 'A' 
'2010.02.01', 'B' 
'2010.03.01', 'E' 
'2010.04.01', 'Z' 

当時の基本支払額を保存する別のテーブル[dbo]。[LEASE_FINANCING_AUDIT_LOG]があります。例えば、私は、このようなエントリを持つことになり、同じレコードの場合:

'2010.01.01', 123 
'2010.04.01', 321 

そのベースの支払いから2010年3月1日まで2010年1月1日から123だったことを意味します(未承認となった)、その後、2010年4月1日からの値となりましたを321

とすることができます。ステータスの変更はさまざまな組み合わせがあり、任意の期間に異なる基本支払い値が存在する可能性があります。

したがって、目標はAPPROVED期間の間にあったLATESTのbase_payment値を見つけることです。

これまでに作成したスクリプトを以下に示します。そのデータと機能を持つ2つのテーブルがあります。他のコードスニペットは単体テストから取得されているため、それらが同じようなものであり、ロジックが期待通りでない場合は「不良」文字列を出力します。この関数は機能していますが、私は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 
+0

[sqlfiddleで質問を追跡しようとする試み](http://sqlfiddle.com/#!6/a2e96/1) –

+0

それ以上8K文字の長さであるように私はバイオリンにそれを置くことはできません。コードを最小限に抑えようとしたときに、他の苦情がありました –

+0

rextester.com dbfiddle.uk db-fiddle.comを試してください。あなたの質問はあまり明確ではありません。 –

答えて

0

代替アプローチについてのご意見をお願いしました。あなたがたとえば、あなたのテーブルON LEASE_APPLICATIONS_AUDIT_LOG.CHANGED_DATE <= LEASE_FINANCING_AUDIT_LOG.CHANGED_DATEに参加することができるように、

  1. は、それがオペレータ等号以外を使用して行うことができる合流覚えている:あなたは、個別にまたは組み合わせて、これらのアイデアを使用することができます。
  2. LAG関数とLEAD関数は、「近くの」レコードを取得するための非常に最適な関数です。 3番目のパラメータでは、レコードが見つからない場合に返される値を指定することもできます。CAST('9999-12-31 23:59:59' AS DATETIMEを挿入するのに便利な場所です。
  3. (WITH句を使用して)Common Table Expressionsを適切に使用することによって達成できる明快さとパフォーマンスを決して過小評価しないでください。
+0

私はこれらの点をすべて知っています。しかし、私はLEAD機能で同じ性能を得ることができませんでした。私が言ったように、これらのクエリは現在私が見つけることができる最高のパフォーマンスを提供しますが、私は実際にどのように書かれているのが嫌いです。 –

+0

あなたは好きではないことは何ですか?行が多すぎますか?入れ子ですか?特定のキーワード?クエリを変更することで達成しようとしていることを説明すると役に立ちます。 –

+0

私は今よりも優れたパフォーマンスを望みます。 –

関連する問題