web-dev-qa-db-ja.com

この数学をビューで実行することは可能ですか?

私はクライアントのビューを作成する任務を負っています。具体的にはビューにある必要があります。ただし、ビュー内で実行する方法がわからない数学があります。それが可能かどうかさえわかりません。しかし、再び、私の心は弱いです。

SQL Server 2008R2を使用しているため、高度なOVER()機能が動作しません。

人が使うために400ドルを与えられているとしましょう。彼らはもっと使うことができますが、最初の$ 400は無料です。レポートの1つの列には、その人が何かに費やした金額が表示され、別の列には、その人が自分のポケットから支払う必要がある合計金額が表示されます。

したがって、この人のレポートの最初のレコードについては、1つの列には50ドルなどの費やした金額があり、2番目の列には0ドルがあります。舞台裏では、彼らはまだ350ドルを費やすことができます。

次のレコードには、300ドルを費やした人がいます。 2列目にはまだ$ 0が表示され、舞台裏では最初の$ 400が$ 50になっています。

その人の3番目のレコードは、彼らが$ 75ドルを費やしたことを示していますが、最初の$ 400から$ 50しか残っていません。 2列目には25ドルの値が含まれているはずです。彼らは最初の$ 400を使い果たし、現在自分のお金を使っています。

4番目のレコードは40ドルを費やしたことを示しているため、2列目には65ドルが表示されます。等...

CTEとテーブル値関数などについて簡単に読みましたが、これらを任意の組み合わせで使用して、上記の望ましい動作を実現できますか?

以下は、構造と望ましい結果のサンプルコードです。

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) 

望ましい結果:

enter image description here

OutOfPocketTotalOutOfPocketと考えることは理にかなっています。

ソースデータには、エントリの順序付けのためのタイムスタンプのようなものはありません。順序はあまり重要ではありません。順序付けが行われた場合は、PlanCodeになります。

制約と、含める必要のなかった3番目の列に基づいて、重複したエントリが発生することはありません。

7
Jeff.Clark

これはPlanCodeでソートされます-重複がある場合は、row_number()を使用します
特定の注文が必要な場合は、その注文を表に含める必要があります

  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 

または

  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 
2
paparazzo

これらの線に沿った何か? OVERSUM句を使用して、積算合計を行うことができます。

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
6
db2

次のスクリプトは、サンプルデータ(およびそのテーブル構造)に基づく厳密にであり、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 

enter image description here

この質問は、テーブル[PayRoll]に主キーがある場合に、より簡単な方法で処理できます。ここにコード全体を入れます:

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)

結果は: enter image description here

5
jyao