SQL Server金额拆分

时间:2015-12-24 13:24:26

标签: sql sql-server

我在SQL Server数据库中有2个表。

客户主要费用表

ReportID CustomerID  TotalExpenseAmount
1000       1          200
1001       2          600

参加者表

ReportID AttendeeName
1000        Mark
1000        Sam
1000        Joe

参与者级别没有金额。我需要手动计算单个与会者金额,如下所述。 (即根据与会者人数拆分TotalExpenseAmount,并确保将个别拆分数字舍入为2位小数,并总计达到TotalExpenseAmount)

最终报告应如下所示:

ReportID CustID AttendeeName TotalAmount AttendeeAmount
1000       1      Mark          200         66.66
1000       1      Sam           200         66.66
1000       1      Joe           200         66.68

最终报告将有大约1,50,000条记录。如果您注意到与会者数量,我已经将总数与总数匹配的方式舍入最后一个。在这种情况下,编写有效SQL查询的最佳方法是什么?

2 个答案:

答案 0 :(得分:3)

您可以使用窗口功能执行此操作:

select ReportID, CustID, AttendeeName, TotalAmount,
       (case when seqnum = 1
             then TotalAmount - perAttendee * (cnt - 1)
             else perAttendee
        end) as AttendeeAmount
from (select a.ReportID, a.CustID, a.AttendeeName, e.TotalAmount,
             row_number() over (partition by reportId order by AttendeeName) as seqnum,
             count(*) over (partition by reportId) as cnt,
             cast(TotalAmount * 1.0 / count(*) over (partition by reportId) as decimal(10, 2)) as perAttendee
      from attendee a join
           expense e
           on a.ReportID = e.ReportID
     ) ae;

perAttendee金额在子查询中计算。这是使用cast()向下舍入的(仅因为floor()不接受小数位参数)。对于其中一行,金额是总减去所有其他与会者的总和。

答案 1 :(得分:0)

做一些类似于@ Gordon的答案,但改用CTE。

with CTECount AS (
                  select a.ReportId, a.AttendeeName, 
                        ROW_NUMBER() OVER (PARTITION BY A.ReportId ORDER BY A.AttendeeName) [RowNum],
                        COUNT(A.AttendeeName) OVER (PARTITION BY A.ReportId) [AttendeeCount],
                        CAST(c.TotalExpenseAmount / (COUNT(A.AttendeeName) OVER (PARTITION BY A.ReportId)) AS DECIMAL(10,2)) [PerAmount]
                  FROM @Customer C INNER JOIN @Attendee A ON A.ReportId = C.ReportID 

                  )
SELECT CT.ReportID, CT.CustomerId, AT.AttendeeName, 
       CASE WHEN CC.RowNum = 1 THEN  CT.TotalExpenseAmount - CC.PerAmount *              (CC.AttendeeCount - 1)
            ELSE CC.PerAmount END [AttendeeAmount]
FROM @Customer CT INNER JOIN @Attendee AT 
        ON CT.ReportID = AT.ReportId 
    INNER JOIN CTECount CC 
        ON CC.ReportId = CT.ReportID AND CC.AttendeeName = AT.AttendeeName

我喜欢CTE,因为它允许我分离查询的不同方面。 @Gordon使用的很酷的东西是Case语句和内部计算,以使行总计正确。