Chạy Total mà đặt lại khi Khách hàng thay đổi (giữ RowNumbers hiện tại) - bao gồm nỗ lực


7

Tôi có một bảng trong đó RowNumber là bản chất. Nó có một loạt các máy khách và tổng số đang chạy cho máy khách đó - sẽ đặt lại mỗi khi Máy khách thay đổi. ví dụ

client  rownr   amount  runtotal
Company A   1   1.00    1.00
Company A   2   1.00    2.00  1+1 = 2
Company A   3   5.00    7.00  2+5 = 7
Company B   4   3.00    3.00  Reset Because Customer B <> Previous Row Customer A
Company A   5   1.00    1.00  Reset Because Customer A <> Previous Row Customer B
Company B   6   2.00    2.00  Reset Because Customer B <> Previous Row Customer A
Company B   7   1.00    3.00  2+1 = 3
Company B   8   5.00    8.00  3+5 = 8

Tôi đã thử sử dụng Phân vùng, nhưng nó luôn Nhóm khách A cùng nhau và Máy khách B cùng nhau - nó loại bỏ phần quan trọng của Số hàng.

Có ai giúp đỡ không?

 drop table #Checks
CREATE TABLE #Checks
(
  Client VARCHAR(32),
  RowNr int,
  Amount DECIMAL(12,2),
  RunTotal DECIMAL(12,2),
  Part int
);

INSERT #Checks(Client, RowNr, Amount)
          SELECT 'Company A', '1', 1
UNION ALL SELECT 'Company A', '2', 1
UNION ALL SELECT 'Company A', '3', 5
UNION ALL SELECT 'Company B', '4', 3
UNION ALL SELECT 'Company A', '5', 1
UNION ALL SELECT 'Company B', '6', 2
UNION ALL SELECT 'Company B', '7', 1
UNION ALL SELECT 'Company B', '8', 5;

-- gets the first entries per client - these amounts are 
-- the base amounts and the other entries are tallied up

with cte as (
            select
                    c1.client
                  , c1.amount
                  , c1.rowNr
                  , case when c1.client <> c2.client then c1.amount else null end amt
            from #Checks as c1
            left join #Checks as C2 on c1.rownr = (c2.rownr + 1)
  )

select
client
, rownr
, amount
, case when isnull(amt,0) > 0 then amt else total end as runtotal
from cte
cross apply (
                select
                       sum(x.amount) as Total
                from cte as x
                where x.rownr <= cte.rownr and cte.client = x.client
            ) as rt
;

Drop table #Checks

Câu trả lời:


4

Làm thế nào về:

SELECT c.client, c.rownr, c.amount
     , runtotal = SUM(e.amount)
FROM   #Checks c
JOIN   #Checks e ON e.RowNr <= c.RowNr AND e.Client = c.Client -- row from c (note <= not <) and all earlier rows
LEFT OUTER JOIN -- rows between with different cli
       #Checks d ON d.RowNr < c.RowNr AND d.RowNr > e.RowNr AND d.Client<>c.Client
WHERE d.RowNr IS NULL -- drop where there is a row between the one from c and the one from e with different client
GROUP BY c.client, c.rownr, c.amount
ORDER BY c.rownr

Sự tham gia đầu tiên đó có thể tốn kém trên một tập dữ liệu lớn nếu một chỉ mục trên máy khách (để có hiệu quả, bạn sẽ cần một chỉ mục trên máy khách, rownr và một trên rownr (mặc dù tôi cho rằng đó sẽ là PK của bạn có nghĩa là chỉ mục đã có)) không được chọn lọc nhiều (nếu sự đa dạng của dữ liệu trong cột máy khách và nó được lan truyền liên quan đến nghĩa là một chỉ số dựa trên nó không được chọn lọc nhiều thì lần đầu tiên tham gia sẽ gần với một sản phẩm của cartesian như làm cho không có tỷ lệ cược).


6

Điều này sẽ làm những gì bạn muốn:

WITH CTE AS
(
    SELECT  *, 
            RN = ROW_NUMBER() OVER(PARTITION BY Client ORDER BY RowNr)
    FROM #Checks
), CTE2 AS
(
    SELECT  *, 
            RN2 = RowNr - RN 
    FROM CTE 
)
SELECT A.Client, A.RowNr, A.Amount, B.RunTotal
FROM CTE2 A
CROSS APPLY (SELECT SUM(Amount) RunTotal
             FROM CTE2
             WHERE Client = A.Client
             AND RN2 = A.RN2
             AND RowNr <= A.RowNr) B
ORDER BY RowNr

Các kết quả:

╔═══════════╦═══════╦════════╦══════════╗
  Client    RowNr  Amount  RunTotal 
╠═══════════╬═══════╬════════╬══════════╣
 Company A      1  1.00    1.00     
 Company A      2  1.00    2.00     
 Company A      3  5.00    7.00     
 Company B      4  3.00    3.00     
 Company A      5  1.00    1.00     
 Company B      6  2.00    2.00     
 Company B      7  1.00    3.00     
 Company B      8  5.00    8.00     
╚═══════════╩═══════╩════════╩══════════╝

4

Câu đố SQL

Thiết lập lược đồ MS SQL Server 2008 :

CREATE TABLE dbo.Checks
(
  Client VARCHAR(32),
  RowNr int,
  Amount DECIMAL(12,2),
  RunTotal DECIMAL(12,2),
  Part int
);

INSERT dbo.Checks(Client, RowNr, Amount)
          SELECT 'Company A', '1', 1
UNION ALL SELECT 'Company A', '2', 1
UNION ALL SELECT 'Company A', '3', 5
UNION ALL SELECT 'Company B', '4', 3
UNION ALL SELECT 'Company A', '5', 1
UNION ALL SELECT 'Company B', '6', 2
UNION ALL SELECT 'Company B', '7', 1
UNION ALL SELECT 'Company B', '8', 5;

Truy vấn 1 :

WITH Islands AS
(
  SELECT Client, RowNr, Amount, RowNr-ROW_NUMBER()OVER(PARTITION BY Client ORDER BY RowNr) IslId
  FROM Checks
)


SELECT *
FROM Islands I1
CROSS APPLY(
  SELECT SUM(Amount) RunningTotal
  FROM Islands I2
  WHERE I1.Client = I2.Client
  AND I1.IslId = I2.IslId
  AND I1.RowNr >= I2.RowNr
)C

Kết quả :

|    CLIENT | ROWNR | AMOUNT | ISLID | RUNNINGTOTAL |
-----------------------------------------------------
| Company A |     1 |      1 |     0 |            1 |
| Company A |     2 |      1 |     0 |            2 |
| Company A |     3 |      5 |     0 |            7 |
| Company A |     5 |      1 |     1 |            1 |
| Company B |     4 |      3 |     3 |            3 |
| Company B |     6 |      2 |     4 |            2 |
| Company B |     7 |      1 |     4 |            3 |
| Company B |     8 |      5 |     4 |            8 |
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.