我有一个包含以下列的表:
Document_ID, Customer_ID, Date, LoanedMoney.
我已经创建了一个新的LoanedDate
列。我希望以下列方式填写日期LoanedDate
:
Date
或上一个日期不存在(并不总是指-1天),且Document_ID
和Customer_ID
为空,则为>复制LoanedMoney
值并使用该值更新; Date
和Document_ID
的上一个Customer_ID
(并不总是指-1天)不为空 - >复制它并使用该值更新; NULL
设置为LoanedDate
我确定前一个日期的近似逻辑(不知道如何将它放在case语句中):
SELECT TOP 1 Z1.Date
FROM DBANME Z1
LEFT JOIN DBNAME Z2
ON Z1.Document_ID = Z2.Document_ID AND Z1.Customer_ID = Z2.Customer_ID AND CONVERT(CHAR(8), Z1.Date, 112) < CONVERT(CHAR(8), Z2.Date, 112)
ORDER BY Date DESC
我做过这样的事情:
DECLARE @Min datetime, @Prev datetime
SELECT @Min = MIN(Date) FROM DBNAME
UPDATE DBNAME
SET LoanedDate CASE
WHEN (LoanedMoney > 0)
-- SET @Prev =
CASE WHEN @Prev IS NULL THEN Date
ELSE @Prev
ELSE NULL
实施它的最佳方法是什么?
我有什么:
Document_ID, Customer_ID, Date, LoanedMoney, LoanedDate
1, 1, 2012-04-30, 30, NULL
1, 1, 2012-04-29, 50, NULL
1, 1, 2012-04-28, 50, NULL
1, 1, 2012-04-27, 0, NULL
1, 1, 2012-04-26, 20, NULL
我的期望:
Document_ID, Customer_ID, Date, LoanedMoney, LoanedDate
1, 1, 2012-04-30, 30, 2012-04-28
1, 1, 2012-04-29, 50, 2012-04-28
1, 1, 2012-04-28, 50, 2012-04-28
1, 1, 2012-04-27, 0, NULL -- Because LoanedMoney = 0
1, 1, 2012-04-26, 20, 2012-04-26
答案 0 :(得分:0)
尝试这样的事情 - 只需要执行所有规则的几个相关子查询。第一个子查询是查找小于当前的所有日期,第二个查询是在最新的LoanedMoney = 0之后消除值。从中选择MIN,如果它为空,则使用COALESCE将其替换为当前日期。
UPDATE z1
SET LoanedDate =
CASE WHEN LoanedMoney = 0 THEN NULL
ELSE
COALESCE (
(SELECT MIN(DATE)
FROM DBNAME z2
WHERE z1.Customer_ID = z2.Customer_ID
AND z1.Document_ID = z2.Document_ID
AND z2.Date < z1.Date
AND z2.Date > (SELECT MAX(DATE)
FROM dbo.DBNAME z3
WHERE z3.Customer_ID = z2.Customer_ID
AND z3.Document_ID = z2.Document_ID
AND z3.Date < z1.Date
AND z3.LoanedMoney = 0)
), Date) END
FROM dbo.DBNAME z1
<强> SQLFiddle DEMO 强>
编辑 - 选项2
这是另一种使用ROW_NUMBER()
函数和recursive CTE等不同概念的方法。可能有点难以理解,但它会胜过大表上的第一个查询。
WITH CTE_Prep AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY Document_ID, Customer_ID ORDER BY [DATE]) RN
FROM DBNAME
)
,RCTE AS
(
SELECT *, CASE WHEN LoanedMoney>0 THEN Date END AS LoanedDate2
FROM CTE_Prep
WHERE RN = 1
UNION ALL
SELECT p.*, CASE WHEN p.LoanedMoney=0 THEN NULL
ELSE CASE WHEN r.LoanedDate2 IS NULL THEN p.Date
ELSE r.LoanedDate2 END
END AS LoanedDate2
FROM CTE_Prep p
INNER JOIN RCTE r
ON p.Customer_ID = r.Customer_ID
AND p.Document_ID = r.Document_ID
AND p.RN = r.RN + 1
)
UPDATE z
SET z.LoanedDate = r.LoanedDate2
FROM RCTE r
INNER JOIN dbo.DBNAME z ON r.Customer_ID = z.Customer_ID
AND r.Document_ID = z.Document_ID
AND r.Date = z.Date;
<强> SQLFiddleDEMO 强>