【问题标题】:Fill missing months in a SELECT query在 SELECT 查询中填写缺失的月份
【发布时间】:2019-03-28 15:41:12
【问题描述】:

我正在尝试在 SELECT 查询中填充缺失的月份。 它看起来像这样:

SELECT sl.loonperiode_dt, (sum(slr.uren)) code_220
FROM HR.soc_loonbrief_regels slr,
             HR.soc_loonbrieven sl,
             HR.werknemers w,
             HR.v_kontrakten vk 
WHERE sl.loonperiode_dt BETWEEN '01012018' AND '01122018'
         AND slr.loon_code_id IN (394)
         AND slr.loonbrief_id = sl.loonbrief_id
         AND w.werknemer_id   = sl.werknemer_id
         AND w.werknemer_id   = vk.werknemer_id
         AND vk.functie_id    IN (121, 122, 128)
         AND sl.loonperiode_dt BETWEEN hist_start_dt AND last_day(nvl(hist_eind_dt, sl.loonperiode_dt))
         AND w.afdeling_id  like '961'
GROUP BY sl.loonperiode_dt
ORDER BY sl.loonperiode_dt

它输出这个表:

31/01/18    234
30/04/18    245,8
31/05/18    714,6
31/07/18    288,04
31/08/18    281
30/11/18    515,12

我显然希望它是这样的:

31/01/18    234
28/02/18    0
31/03/18    0
30/04/18    245,8
31/05/18    714,6
30/06/18    0
31/07/18    288,04
31/08/18    281
30/09/18    0
31/10/18    0
30/11/18    515,12
31/12/18    0

我有一个日历表“CONV_HC.calendar”,其日期位于名为“DAT”的列中。 我已经看到了很多关于此的问题和答案,但我不知道如何将 LEFT JOIN 方法或任何其他方法应用于我当前的问题。

非常感谢,

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    您可以有一个已经完成的带有月份的表,然后“加入”它,按日期分组,或者您可以使用子查询或使用 with 语句创建一个,例如

    WITH Months (month) AS (
      SELECT 1 AS Month FROM DUAL
    
      UNION ALL
    
      SELECT MONTH + 1
      FROM Months
      WHERE MONTH < 12
    )
    SELECT *
    FROM Months
    
        LEFT JOIN SomeTable
        ON SomeTable.month = Months.MONTH
        --ON Extract(MONTH FROM SomeTable.date) = Months.MONTH
    

    编辑

    一个更好的例子:

    --Just to simulate some table data
    WITH SomeData AS (
      SELECT TO_DATE('01/01/2019', 'MM/DD/YYYY') AS Dat, 5 AS Value FROM dual
      UNION ALL
      SELECT TO_DATE('01/05/2019', 'MM/DD/YYYY') AS Dat, 7 AS Value FROM dual
      UNION ALL
      SELECT TO_DATE('03/03/2019', 'MM/DD/YYYY') AS Dat, 2 AS Value FROM dual
      UNION ALL
      SELECT TO_DATE('11/05/2019', 'MM/DD/YYYY') AS Dat, 9 AS Value FROM dual
    )
    , Months (StartDate, MaxYear) AS (
      SELECT CAST(TO_DATE('01/01/2019', 'MM/DD/YYYY') AS DATE) AS StartDate, 2019 AS MaxYear FROM DUAL
    
      UNION ALL
    
      SELECT CAST(ADD_MONTHS(StartDate, 1) AS DATE), MaxYear
      FROM Months
      WHERE EXTRACT(YEAR FROM ADD_MONTHS(StartDate, 1)) <= MaxYear 
    )
    SELECT
        Months.StartDate AS Dat
        , SUM(SomeData.Value) AS SumValue 
    FROM Months
    
        LEFT JOIN SomeData
        ON Extract(MONTH FROM SomeData.Dat) = Extract(MONTH FROM Months.StartDate)
    
    GROUP BY 
        Months.StartDate
    

    编辑

    您不会找到只是复制过去的解决方案,您需要从中获取想法并更改您的上下文。

    让我们试试这个。您可以在APP中“添加”缺少的月份,或者您可以将它与已经完成的表格一起加入,不需要是真正的表格,您可以制作一张。 with 语句就是一个例子。因此,让我们在 2019 年的最后一天获得整个月:

    --Geting the last day of every month for 2019
    WITH Months (CurrentMonth, MaxYear) AS (
      SELECT CAST(TO_DATE('01/01/2019', 'MM/DD/YYYY') AS DATE) AS CurrentMonth, 2019 AS MaxYear FROM DUAL
    
      UNION ALL
    
      SELECT CAST(ADD_MONTHS(CurrentMonth, 1) AS DATE), MaxYear
      FROM Months
      WHERE EXTRACT(YEAR FROM ADD_MONTHS(CurrentMonth, 1)) <= MaxYear  
    )
    SELECT LAST_DAY(Months.CurrentMonth) AS LastDay
    FROM Months
    

    好的,现在我们所有月份都可以加入。在您的查询中,您已经完成了总和,因此让我们跳过总和并使用您的数据。只需添加另一个 with 查询。

    --Geting the last day of every month for 2018
    WITH Months (CurrentMonth, MaxYear) AS (
      SELECT CAST(TO_DATE('01/01/2018', 'MM/DD/YYYY') AS DATE) AS CurrentMonth, 2018 AS MaxYear FROM DUAL
    
      UNION ALL
    
      SELECT CAST(ADD_MONTHS(CurrentMonth, 1) AS DATE), MaxYear
      FROM Months
      WHERE EXTRACT(YEAR FROM ADD_MONTHS(CurrentMonth, 1)) <= MaxYear  
    )
    , YourData as (
        SELECT sl.loonperiode_dt, (sum(slr.uren)) code_220
        FROM HR.soc_loonbrief_regels slr,
                     HR.soc_loonbrieven sl,
                     HR.werknemers w,
                     HR.v_kontrakten vk 
        WHERE sl.loonperiode_dt BETWEEN '01012018' AND '01122018'
                 AND slr.loon_code_id IN (394)
                 AND slr.loonbrief_id = sl.loonbrief_id
                 AND w.werknemer_id   = sl.werknemer_id
                 AND w.werknemer_id   = vk.werknemer_id
                 AND vk.functie_id    IN (121, 122, 128)
                 AND sl.loonperiode_dt BETWEEN hist_start_dt AND last_day(nvl(hist_eind_dt, sl.loonperiode_dt))
                 AND w.afdeling_id  like '961'
        GROUP BY sl.loonperiode_dt
        --ORDER BY sl.loonperiode_dt
    )
    SELECT
        LAST_DAY(Months.CurrentMonth) AS LastDay
        , COALESCE(YourData.code_220, 0) AS code_220
    FROM Months
    
        Left Join YourData
        on Extract(MONTH FROM Months.CurrentMonth) = Extract(MONTH FROM YourData.loonperiode_dt)
        --If you have more years: AND Extract(YEAR FROM Months.CurrentMonth) = Extract(YEAR FROM YourData.loonperiode_dt)
    
    ORDER BY LastDay ASC
    

    【讨论】:

    • 就像我说的,我不能让它工作。我试图提供足够的示例来获得对我的特定示例的帮助。您的答案可能是正确的,但我可以在 Stackoverflow 上找到相同的查询,但这对我没有帮助。
    • 只需使用 SomeData 将您的查询放入第一个查询并更改左连接中的字段名称,在第一个 Month 查询中调整您的日期间隔
    • 好的,所以我将其更改为有一个更好的示例并解释它是如何完成的。
    • 非常感谢!我对 SQL 不够熟悉,无法轻松理解我所说的 not-simple-enough-sql-queries,但您以清晰而巧妙的方式解释了它。感谢您的宝贵时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-27
    • 2011-08-21
    • 2022-07-16
    相关资源
    最近更新 更多