【发布时间】:2017-10-26 15:57:00
【问题描述】:
我很难写出好标题,所以我将尝试在这里详细描述问题。
我们有表 [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 期间之间的 LATEST base_payment 值。
这是我们目前制作的脚本。有 2 个包含该数据和函数的表。其他代码 sn-ps 取自单元测试,这就是为什么它们会这样,如果逻辑不符合预期,它们将输出“坏”字符串。该功能正在运行,但我不太喜欢 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
【问题讨论】:
-
我不能把它放在小提琴上,因为它的长度超过了 8k 个字符。当我试图最小化代码时,它还有其他抱怨
-
尝试 rextester.com dbfiddle.uk db-fiddle.com 如果有 6 个测试,请指定它们是什么。你的问题不是很清楚。
-
@Used_By_Already 我无法将我的查询导入到您提供的任何服务中。但是我修改了查询。将其复制/粘贴到 SSMS(在任何数据库上)并执行它。您将了解测试的含义。
标签: sql sql-server tsql sql-server-2014