0

我有一个包含以下列的表格:

Document_ID, Customer_ID, Date, LoanedMoney.

我创建了一个新LoanedDate列。我想LoanedDate通过以下方式填写日期:

  1. 如果前一个Date或前一个日期不存在(它并不意味着总是-1天)Document_ID并且Customer_ID为空 -> 复制LoanedMoney值并使用该值更新;
  2. 如果前一个Date(并不意味着总是-1天)具有相同Document_ID且不Customer_ID为空->复制它并使用该值进行更新;
  3. 其他设置NULLLoanedDate

我确定上一个日期的大致逻辑(不知道如何将其放在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
4

1 回答 1

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 演示

编辑 - 选项 2

这是另一种方法,使用不同的概念,如ROW_NUMBER()函数和递归 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

于 2013-10-28T15:27:50.757 回答