Có thể làm toán này trong một quan điểm?


7

Tôi đã được giao nhiệm vụ tạo ra một khung nhìn cho một khách hàng. Cụ thể nó phải ở trong một cái nhìn . Tuy nhiên, có một số phép toán mà tôi không chắc chắn cách thực hiện trong một khung nhìn. Tôi không biết nếu nó thậm chí có thể. Nhưng sau đó, một lần nữa, tâm trí của tôi là yếu đuối.

Tôi đang sử dụng SQL Server 2008R2, vì vậy OVER()chức năng nâng cao không hoạt động.

Giả sử một người được cho 400 đô la để chi tiêu. Họ có thể chi tiêu nhiều hơn, nhưng $ 400 đầu tiên là miễn phí. Một cột của báo cáo sẽ có số tiền mà người đó đã chi cho một thứ gì đó, và một cột khác sẽ có tổng số tiền mà người đó cần phải trả bằng tiền túi của họ.

Vì vậy, đối với bản ghi đầu tiên trong báo cáo cho người này, một cột sẽ có số tiền họ đã chi tiêu, giả sử là 50 đô la, và sau đó một cột thứ hai sẽ có 0 đô la. Đằng sau hậu trường họ vẫn còn 350 đô la để chi tiêu.

Kỷ lục tiếp theo có người chi 300 đô la. Cột thứ hai vẫn sẽ hiển thị $ 0 và đằng sau hậu trường, $ 400 ban đầu bây giờ là $ 50.

Kỷ lục thứ ba cho người này cho thấy họ đã chi 75 đô la, nhưng họ chỉ còn lại 50 đô la so với 400 đô la ban đầu. Cột thứ hai bây giờ sẽ có giá trị $ 25 trong đó. Họ đã cạn kiệt 400 đô la ban đầu và hiện đang tiêu tiền của chính họ.

Bản ghi thứ tư cho thấy họ đã chi 40 đô la, vì vậy bây giờ cột thứ hai sẽ hiển thị 65 đô la. Vân vân...

Tôi đã đọc ngắn gọn về CTE và các hàm có giá trị của bảng và như vậy, nhưng liệu có thể sử dụng chúng trong bất kỳ kết hợp nào để đưa ra hành vi mong muốn ở trên không?

Dưới đây là một số mã mẫu cho cấu trúc và kết quả mong muốn

CREATE TABLE Payroll (
    PersonID int,
    PlanCode varchar(10),
    Deduction int NULL
)
GO

INSERT INTO Payroll (PersonID, PlanCode, Deduction)
VALUES (1, 'Medical', 200)
  ,(1, 'Dental', 250)
  ,(1, 'Vision', 300)
  ,(2, 'Medical', 100)
  ,(2, 'Dental', 150)
  ,(2, 'Vision', 100)
  ,(2, 'Disability', 100)
  ,(2, 'Life', 140) 

Kết quả mong muốn:

nhập mô tả hình ảnh ở đây

Nó có thể có ý nghĩa để nghĩ về OutOfPocketnhư TotalOutOfPocket.

Không có gì giống như dấu thời gian trong dữ liệu nguồn để sắp xếp các mục. Việc đặt hàng không quá quan trọng. Nếu bất kỳ đặt hàng được thực hiện, nó sẽ được trên PlanCode.

Dựa trên các ràng buộc của chúng tôi và cột thứ 3 không cần thiết phải đưa vào, sẽ không có bất kỳ mục trùng lặp nào có thể.


Đọc điều này: Cách tiếp cận tốt nhất để chạy tổng số Nó có một số phương pháp hoạt động trong các phiên bản cũ hơn trước năm 2012. Hãy thử con trỏ nếu bạn muốn hiệu quả nhất. Một chỉ mục trên (PersonID, PlanCode) INCLUDE (Deduction)sẽ giúp các truy vấn (bất cứ bạn chọn sử dụng).
ypercubeᵀᴹ

Câu trả lời:


2

sắp xếp này trên PlanCode - nếu bạn có các bản sao thì hãy sử dụng row_number ()
nếu bạn cần một thứ tự cụ thể thì bạn cần phải có thứ tự đó trong bảng

  select PersonID, PlanCode, Deduction, [sum]
       , case when [sum] < 400 then 0 else [sum] - 400 end as oop
  from
  ( select p1.PersonID, p1.PlanCode, p1.Deduction 
         , ( select sum(p2.Deduction) 
               from payroll p2  
              where p2.PersonID  = p1.PersonID 
                and p2.PlanCode <= p1.PlanCode ) as [sum] 
    from payroll p1 
  ) tt
  order by tt.PersonID, tt.PlanCode 

hoặc là

  select p1.PersonID, p1.PlanCode, p1.Deduction 
       , case  when sum(p2.Deduction) < 400 then 0 else sum(p2.Deduction) - 400 end as OOP
  from payroll p1 
  join payroll p2  
        on p2.PersonID  = p1.PersonID 
       and p2.PlanCode <= p1.PlanCode  
 group by p1.PersonID, p1.PlanCode, p1.Deduction 

Aaaaaaaand Tôi chỉ vô tình trao tiền thưởng cho jyao. Tôi bắt đầu nghĩ rằng tôi không thể hoạt động mà không có cà phê. Mặt khác, một yêu cầu đã thay đổi đủ để thay đổi câu hỏi mà tôi không thể tìm ra cách sử dụng mã của bạn với yêu cầu mới. Nếu bạn muốn xem qua, tôi đã đăng câu hỏi lên CodeReview. ( codereview.stackexchange.com/questions/143899/ mẹo )
Jeff.Clark

6

Một cái gì đó dọc theo những dòng này có thể? Bạn có thể thực hiện chạy tổng cộng với OVERmệnh đề cho SUM.

CREATE TABLE Expenses (
    expense_id int NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED,
    amount decimal(19,5)
)

INSERT INTO Expenses (amount) VALUES (50), (300), (75), (40)
GO

WITH running_total AS (
    SELECT
        expense_id,
        amount,
        SUM(amount) OVER (ORDER BY expense_id ROWS UNBOUNDED PRECEDING) AS total
    FROM Expenses
)
SELECT
    expense_id,
    amount,
    total,
    CASE WHEN total > 400 THEN total - 400 ELSE 0 END AS out_of_pocket_total
FROM running_total
ORDER BY expense_id

Để làm điều này là XEM, thêm CREATE VIEW [ViewName] AStrước WITH running_totaldòng. Bạn cũng sẽ cần phải loại bỏ ORDER BYở cuối; XEM không hỗ trợ ORDER BYtrong định nghĩa. Bạn có thể áp dụng cùng một tuyên bố khi truy vấn XEM.
Steven Hibble

ALAS, tôi đang sử dụng SqlServer 2008 R2, vì vậy mọi thứ nằm ngoài QUÁ (Phân vùng theo thứ tự) không hoạt động :(
Jeff.Clark

1
@ Jeff.Clark Bummer! Bạn có thể có thể nhận được kết quả tương tự bằng cách thay thế SUM () bằng truy vấn con tương quan, với chi phí có thể có của một số hiệu suất.
db2

5

Tập lệnh sau hoàn toàn dựa trên dữ liệu mẫu của bạn (và cấu trúc bảng của nó) và có thể chạy được cho SQL Server 2008.

; with c as (
select personid, plancode, deduction
     , rownum=ROW_NUMBER() over (partition by PersonID order by personid )
from dbo.Payroll
)
, c2 as (
select personid, plancode, deduction, T.ytd
from c
cross apply (select ytd = sum(deduction) 
             from c cc 
             where c.PersonID = cc.PersonID 
             and c.rownum >= cc.rownum) T(ytd)
)
select personid, plancode, deduction, 
       OutOfPoket = case when 400 > ytd then 0 else ytd-400 end
from c2 

nhập mô tả hình ảnh ở đây

Câu hỏi này có thể có cách xử lý đơn giản hơn nếu bảng [PayRoll] có khóa chính. Tôi đặt toàn bộ mã ở đây:

use tempdb
drop table dbo.Payroll
CREATE TABLE Payroll (
    id int identity primary key, -- assume there is a PK here
    PersonID int,
    PlanCode varchar(10),
    Deduction int NULL
)
GO

INSERT INTO Payroll (PersonID, PlanCode, Deduction)
VALUES (1, 'Medical', 200)
  ,(1, 'Dental', 250)
  ,(1, 'Vision', 300)
  ,(1, 'Medical', 111) -- additional row (though not needed as per comments by original owner, but just for fun of adding more complexity)
  ,(2, 'Medical', 100)
  ,(2, 'Dental', 150)
  ,(2, 'Vision', 100)
  ,(2, 'Disability', 100)
  ,(2, 'Life', 140) 
go


-- easier solution
select personid, plancode, deduction
,OutOfPocket= case when T.ytd > 400 then t.Ytd-400 else 0 end
from dbo.Payroll c
cross apply (
            select ytd = sum(deduction) 
            from dbo.Payroll cc 
            where c.PersonID = cc.PersonID and c.ID >=cc.ID)  T(ytd)

Kết quả là: nhập mô tả hình ảnh ở đây


Ồ! thật thú vị. Dữ liệu thực tế có khóa chính. Trong sự thiếu hiểu biết của tôi, tôi đã không nghĩ rằng nó quan trọng. Sự khác biệt đó sẽ tốt cho tôi nhớ trong tương lai. Tôi sẽ tiếp tục thực hiện các giải pháp này. Nếu bạn có thể, hãy giữ cả hai và không có giải pháp chính trong đó để tôi có thể so sánh chúng với việc học của riêng tôi.
Jeff.Clark
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.