查询从日期间隔开始应用费率

时间:2015-11-24 17:32:25

标签: sql oracle

假设我的oracle数据库中有两个表

表A:stDate,endDate,薪水

例如:

03/02/2010 28/02/2010 2000
05/03/2012 29/03/2012 2500

表B:DateOfActivation,rate

例如:

01/01/2010 1.023
01/11/2011 1.063
01/01/2012 1.075

我想有一个SQL查询,显示表A的工资总和,每个工资乘以表B的比率,具体取决于激活日期。

这里,对于第一个工资,优惠利率是第一个(1.023),因为第二个利率的激活日期晚于stDate和endDate间隔。 对于第二个工资,应用第三个工资,因为工资的激活日期在第二个工资的日期之间。

所以总和就是这个:2000 * 1.023 + 2500 * 1.075 = 4733.5

我希望我很清楚

由于

3 个答案:

答案 0 :(得分:0)

假设速率必须在间隔开始之前有效(即DateOfActivation< stDate),你可以这样做(see fiddle):

SELECT SUM(salary* (SELECT rate from TableB WHERE DateOfActivation= (SELECT MAX(DateOfActivation) FROM TableB WHERE DateOfActivation < stDate) )) FROM TableA;

答案 1 :(得分:0)

如果DateofActivation是具有rate_start_date和rate_end_date的真实有效日期表,则无法创建新行,其开始日期或end_date将位于现有的rate_start_date - rate_end_date对中,此问题变得更加容易。当前活动的行通常具有rate_end_date的NULL值。另外,可能,您希望工资表上的EMP_ID能够对行进行求和以完成计算;人们需要考虑以下情况:

 Start Date is between rate_start and rate_end
 End Date is  between rate_start and rate_end
 Rate_start and Rate_end are between start_date and end_date (sandwiched)

如果您运行以下代码段,您会看到我们可以按照以下方式人为创建rate_end_dates:

       SELECT D.ACTIVEDATE, D.RATE, NVL(MIN(E.ACTIVEDATE)-1,SYSDATE) ENDDATE
       FROM XX_DATEOFACTIVATION D, XX_DATEOFACTIVATION E
       WHERE D.ACTIVEDATE<E.ACTIVEDATE(+)
       GROUP BY D.ACTIVEDATE, D.RATE
       ORDER BY D.ACTIVEDATE 

建议的代码如下:

    SELECT DISTINCT * FROM
     (SELECT S.*, T.RATE, S.SALARY*T.RATE
     FROM  XX_SAL_HIST S, 
    (SELECT D.ACTIVEDATE, D.RATE, NVL(MIN(E.ACTIVEDATE)-1,SYSDATE) ENDDATE
      FROM XX_DATEOFACTIVATION D, XX_DATEOFACTIVATION E
      WHERE D.ACTIVEDATE<E.ACTIVEDATE(+) 
      GROUP BY D.ACTIVEDATE, D.RATE) T  -- creating synthetic rate_end_date
     WHERE S.STDATE BETWEEN T.ACTIVEDATE AND T.ENDDATE)
     UNION
    (SELECT S.*, T.RATE, S.SALARY*T.RATE
     FROM  XX_SAL_HIST S, 
     (SELECT D.ACTIVEDATE, D.RATE, NVL(MIN(E.ACTIVEDATE)-1,SYSDATE) ENDDATE
       FROM XX_DATEOFACTIVATION D, XX_DATEOFACTIVATION E
       WHERE D.ACTIVEDATE<E.ACTIVEDATE(+)
       GROUP BY D.ACTIVEDATE, D.RATE) T  -- creating synthetic rate_end_date
     WHERE S.ENDDATE BETWEEN T.ACTIVEDATE AND T.ENDDATE)
    UNION
     (SELECT S.*, T.RATE, S.SALARY*T.RATE
     FROM  XX_SAL_HIST S, 
     (SELECT D.ACTIVEDATE, D.RATE, NVL(MIN(E.ACTIVEDATE)-1,SYSDATE) ENDDATE
       FROM XX_DATEOFACTIVATION D, XX_DATEOFACTIVATION E
       WHERE D.ACTIVEDATE<E.ACTIVEDATE(+)
       GROUP BY D.ACTIVEDATE, D.RATE) T  -- creating synthetic rate_end_date
     WHERE T.ACTIVEDATE BETWEEN S.STDATE AND S.ENDDATE)

答案 2 :(得分:0)

要做的第一件事是转换Table B(查询中的Table2),以便为每一行开始和结束日期

Select DateOfActivation AS startDate
     , rate
     , NVL(LEAD(DateOfActivation, 1) OVER (ORDER BY DateOfActivation)
         , TO_DATE('9999/12/31', 'yyyy/mm/dd')) AS endDate
From   Table2

现在我们可以使用Table A(查询中的Table1

加入此表格
WITH Rates AS (
  Select DateOfActivation AS startDate
       , rate
       , NVL(LEAD(DateOfActivation, 1) OVER (ORDER BY DateOfActivation)
           , TO_DATE('9999/12/31', 'yyyy/mm/dd')) AS endDate
  From   Table2)
Select SUM(s.salary * r.rate)
From   Rates r
       INNER JOIN Table1 s ON s.stDate < r.endDate AND s.endDate > r.startDate

JOIN条件会使Table A中的每一行至少部分处于费率的激活期内,如果您需要包含它,则可以按以下查询更改

WITH Rates AS (
  Select DateOfActivation AS startDate
       , rate
       , NVL(LEAD(DateOfActivation, 1) OVER (ORDER BY DateOfActivation)
           , TO_DATE('9999/12/31', 'yyyy/mm/dd')) AS endDate
  From   Table2)
Select SUM(s.salary * r.rate)
From   Rates r
       INNER JOIN Table1 s ON s.stDate >= r.startDate AND s.endDate <= r.endDate