4

我需要帮助来计算任何帐户的周转时间,以便从负每日余额变为正数。例如,帐户 12345 在 2013 年 4 月 5 日为正数,但在 04/06、04/07、04/08(三天)的余额为负数,第四天变为正数。我想开发一个查询来计算周转时间(4 天)。

Account Number  Transaction Date    Daily Balance
    12345       4/1/2013            304
    12345       4/2/2013            -78
    12345       4/3/2013            -65
    12345       4/4/2013            12
    12345       4/5/2013            25
    12345       4/6/2013            -345
    12345       4/7/2013            -450
    12345       4/8/2013            -650
    12345       4/9/2013            105
    12345       4/10/2013           110
    110000      4/1/2013            150
    110000      4/2/2013            -15
    110000      4/3/2013            -56
    110000      4/4/2013            -35
    110000      4/5/2013            -15
    110000      4/6/2013            106
    110000      4/7/2013            500
    110000      4/8/2013            -150
    110000      4/9/2013            50
    110000      4/10/2013           100
    55544       4/1/2013            150
    55544       4/2/2013            120
    55544       4/3/2013            -145
    55544       4/4/2013            -250
    55544       4/5/2013            15
    55544       4/6/2013            20
    55544       4/7/2013            40
    55544       4/8/2013            50
    55544       4/9/2013            -10
    55544       4/10/2013           60

我正在尝试从上表中获得以下结果。该查询将应用于具有数千行的事务表。因此,我需要帮助来构建一些有效的查询来计算以下结果。

Account Number  Turnover time for an account to become positive
12345           3
12345           4
110000          5
110000          2
55544           3
55544           2

我正在使用 MS SQL 服务器版本 2008。

是的,有零。他们被认为是积极的。我的意思是当余额从负数变为0或正数时,将被视为营业额。

Fadi Hassan 提供的解决方案是最高效且易于实施的。尽管它有一个挑战,例如一开始账户余额为负数,但它不起作用。例如,当余额为-110、-40、0、10、90、30、0、-10、-20、0时,将不起作用。

在此处输入图像描述

如果有人有更好的解决方案,请提供帮助。

4

4 回答 4

1

假设版本 >= SQL Server 2005。有两件事要记住。1. 零账户余额如何处理?2. 查询四次扫描表。所以效率不是很高。

;WITH cte AS(
SELECT t1.AccountNumber, t1.TransactionDate, t1.DailyBalance, NextRowDailyBalance
FROM #Accounts t1
CROSS APPLY (SELECT TOP 1 DailyBalance AS NextRowDailyBalance FROM #Accounts t2 WHERE t1.AccountNumber = t2.AccountNumber AND t1.TransactionDate < t2.TransactionDate ORDER BY t2.TransactionDate)t
WHERE (DailyBalance < 0 AND NextRowDailyBalance>0) OR (DailyBalance > 0 AND NextRowDailyBalance < 0)
)
SELECT a1.AccountNumber, DATEDIFF(Day,a1.TransactionDate,t.NRTransactionDate) + 1 AS TurnOverDate
FROM cte a1
CROSS APPLY (SELECT TOP 1 TransactionDate AS NRTransactionDate FROM cte a2 WHERE a1.AccountNumber = a2.AccountNumber AND a1.TransactionDate < a2.TransactionDate ORDER BY a2.TransactionDate)t
WHERE a1.DailyBalance>0
于 2013-04-18T05:16:15.440 回答
1

我希望这就是你要找的@prem(编辑)

    SELECT  *
FROM    (
        SELECT  a.[Account Number],
            a.[Transaction Date],
            a.[Daily Balance],
            DATEDIFF(dd, ISNULL(    (
                        SELECT  MAX(c.[Transaction Date])
                        FROM    Accounts c
                        WHERE   c.[Account Number] = a.[Account Number]
                            AND c.[Transaction Date] < a.[Transaction Date]
                            AND c.[Daily Balance] >= 0
                        ),
                        (
                        SELECT  DATEADD(dd, -1, MIN(c.[Transaction Date]))
                        FROM    Accounts c
                        WHERE c.[Account Number] = a.[Account Number]
                        )
                        ),
            a.[Transaction Date]) AS dat
        FROM    Accounts a
        WHERE a.[Daily Balance] >= 0
    ) t
WHERE   dat > 1
于 2013-04-18T10:03:18.107 回答
1
;WITH T
     AS (SELECT [Account Number],
                [Transaction Date],
                [Daily Balance],
                MAX([Transaction Date]) 
                          OVER (PARTITION BY [Account Number]) AS FinalAccountTransaction,
                ROW_NUMBER() 
                          OVER (PARTITION BY [Account Number] 
                                    ORDER BY [Transaction Date]) - 
                ROW_NUMBER() 
                          OVER (PARTITION BY [Account Number], 
                                             CASE WHEN [Daily Balance] < 1 THEN 1 END 
                                    ORDER BY [Transaction Date]) AS Grp
         FROM   DailyBalance)
SELECT [Account Number],
       MIN([Transaction Date])                                             AS Start,
       DATEDIFF(DAY, MIN([Transaction Date]), MAX([Transaction Date])) + 2 AS [Turnover time]
FROM   T
WHERE  [Daily Balance] < 1
GROUP  BY [Account Number],
          Grp,
          FinalAccountTransaction
/*If this is the final group then it is not followed by a positive so exclude*/
HAVING MAX([Transaction Date]) <> FinalAccountTransaction
ORDER  BY [Account Number],
          Start 

SQL小提琴

于 2013-09-26T09:35:50.893 回答
0

使用光标检查以下解决方案,相应地修改列名。希望这可以帮助你

-- CREATE temp table with rownum to add row numbers
CREATE TABLE #TurnOverTimeTaken
(
    rownum INT,
    Account_Number INT NULL,
    Daily_Balance INT
)

-- Insert data into the temp table with row number
INSERT INTO #TurnOverTimeTaken
SELECT 
   ROW_NUMBER() OVER(PARTITION BY  Account_Number ORDER BY Account_Number) AS rownum
  ,Account_Number
  ,Daily_Balance
FROM TurnOverTimeTaken

-- Create another temp table to display the result  
CREATE TABLE #Result
(
    Account_Number INT NULL,
    Total INT
)

DECLARE @rownum INT
DECLARE @Account_Number INT
DECLARE @Daily_Balance INT
DECLARE @CurrentVal INT

SET @CurrentVal = 0

--Cursor starts here
DECLARE CountCursor CURSOR 
FOR SELECT rownum, Account_Number, Daily_Balance FROM #TurnOverTimeTaken
OPEN CountCursor
FETCH NEXT FROM CountCursor INTO @rownum, @Account_Number, @Daily_Balance
WHILE @@FETCH_STATUS = 0 
BEGIN
    -- Check Daily_Balance is negative and rownumber is not equal to one and previous Daily_Balance > 0
    IF(@Daily_Balance < 0 AND @rownum <> 1 AND 
    (SELECT Daily_Balance FROM #TurnOverTimeTaken WHERE rownum=@rownum-1 AND Account_Number=@Account_Number) > 0)
    BEGIN
        SET @CurrentVal = @CurrentVal + 1
        INSERT INTO #Result VALUES(@Account_Number, @CurrentVal)
    END
    ELSE IF(@Daily_Balance < 0)
    BEGIN
        INSERT INTO #Result VALUES(@Account_Number, @CurrentVal)
    END

    FETCH NEXT FROM CountCursor INTO @rownum, @Account_Number, @Daily_Balance
END
CLOSE CountCursor
DEALLOCATE CountCursor

--SELECT * FROM #TurnOverTimeTaken

SELECT Account_Number,COUNT(Total)+1 FROM #Result
GROUP BY Account_Number,Total

DROP TABLE #TurnOverTimeTaken
DROP TABLE #Result
于 2013-04-18T09:14:38.680 回答