对于NULL结果,月聚合为0

时间:2018-04-19 22:32:50

标签: sum aggregate

我见过类似的东西,但我无法让它发挥作用:

 SELECT 
      CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CALENDAR_MONTH 
    , CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE
    , CNTRSINTDATA.DIM_CNTRS_TSI_COA.TSI_NOMINAL_ACC
    , CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR
    , SUM (CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.QB_TRANS_AMOUNT) AS CNTRS_ACC_BUDGET

FROM 
      CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI
    , CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY
    , CNTRSINTDATA.DIM_CNTRS_TSI_COA

WHERE
    CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.QB_TRANS_DATE = CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CALENDAR_DATE
    AND CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR LIKE '2017'
    AND CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE = CNTRSINTDATA.DIM_CNTRS_TSI_COA.TSI_NOMINAL_CODE
    AND CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE = '6598'

GROUP BY
    CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI.TSI_NOMINAL_CODE
  , CNTRSINTDATA.DIM_CNTRS_TSI_COA.TSI_NOMINAL_ACC
  , CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CALENDAR_MONTH
  , CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR;`

上述查询返回以下结果:

Feb-17  250
Jul-17  400
Jun-17  654
May-17  654
Oct-17  150
Nov-17  250
Aug-17  250

月-17

由于当月该帐户没有任何交易,我还需要剩下的几个月也回来零。

Jan-17  0
Feb-17  250
Mar-17  0
Apr-17  0
Jul-17  400
Jun-17  654
May-17  654
Oct-17  150
Nov-17  250
Aug-17  250
Sep-17  0
Dec-17  0

有一个日期表,其中所有月份的日期都是VARCHAR2。只是无法获得正确的语法。有人可以帮忙吗?

3 个答案:

答案 0 :(得分:0)

Let's break that down and make it more manageable. Firstly, translate that to SQL-92 join syntax and add some aliases

SELECT 
      dcde.CALENDAR_MONTH 
    , fqtt.TSI_NOMINAL_CODE
    , dctc.TSI_NOMINAL_ACC
    , dcde.CNTRS_FIN_YEAR
    , SUM (fqtt.QB_TRANS_AMOUNT) AS CNTRS_ACC_BUDGET
FROM 
  CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI fqtt
    INNER JOIN CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY dcde
        ON fqtt.QB_TRANS_DATE = dcde.CALENDAR_DATE
  INNER JOIN CNTRSINTDATA.DIM_CNTRS_TSI_COA dctc
        ON AND fqtt.TSI_NOMINAL_CODE = dctc.TSI_NOMINAL_CODE
WHERE
        dcde.CNTRS_FIN_YEAR LIKE '2017'
  AND
        fqtt.TSI_NOMINAL_CODE = '6598'
GROUP BY
    fqtt.TSI_NOMINAL_CODE
  , dctc.TSI_NOMINAL_ACC
  , dcde.CALENDAR_MONTH
  , dcde.CNTRS_FIN_YEAR;

Next, you said that there exists a date record (presumably in CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY), so swap that around

SELECT 
      dcde.CALENDAR_MONTH 
    , fqtt.TSI_NOMINAL_CODE
    , dctc.TSI_NOMINAL_ACC
    , dcde.CNTRS_FIN_YEAR
    , SUM (fqtt.QB_TRANS_AMOUNT) AS CNTRS_ACC_BUDGET
FROM 
    CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY dcde
  INNER JOIN CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI fqtt
        ON fqtt.QB_TRANS_DATE = dcde.CALENDAR_DATE
  INNER JOIN CNTRSINTDATA.DIM_CNTRS_TSI_COA dctc
        ON AND fqtt.TSI_NOMINAL_CODE = dctc.TSI_NOMINAL_CODE
WHERE
        dcde.CNTRS_FIN_YEAR LIKE '2017'
  AND
        fqtt.TSI_NOMINAL_CODE = '6598'
GROUP BY
    fqtt.TSI_NOMINAL_CODE
  , dctc.TSI_NOMINAL_ACC
  , dcde.CALENDAR_MONTH
  , dcde.CNTRS_FIN_YEAR;

Finally, you don't actually want inner joins because that eliminates tuples where there is no match. In this case, you want a left join because you want to have the left value even if no value exists on the right. You also need to coalesce your sum expression to 0 because (for reasons I cannot fathom), the SQL standard defines the sum of a bunch records only containing null as null.

SELECT 
      dcde.CALENDAR_MONTH 
    , fqtt.TSI_NOMINAL_CODE
    , dctc.TSI_NOMINAL_ACC
    , dcde.CNTRS_FIN_YEAR
    , COALESCE(SUM (fqtt.QB_TRANS_AMOUNT), 0) AS CNTRS_ACC_BUDGET
FROM 
    CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY dcde
  LEFT JOIN CNTRSINTDATA.FACT_QUICKBOOKS_TRANS_TSI fqtt
        ON fqtt.QB_TRANS_DATE = dcde.CALENDAR_DATE
  LEFT JOIN CNTRSINTDATA.DIM_CNTRS_TSI_COA dctc
        ON AND fqtt.TSI_NOMINAL_CODE = dctc.TSI_NOMINAL_CODE
WHERE
        dcde.CNTRS_FIN_YEAR LIKE '2017'
  AND
        fqtt.TSI_NOMINAL_CODE = '6598'
GROUP BY
    fqtt.TSI_NOMINAL_CODE
  , dctc.TSI_NOMINAL_ACC
  , dcde.CALENDAR_MONTH
  , dcde.CNTRS_FIN_YEAR;

Give that a try and see if it is what you want

答案 1 :(得分:0)

Here is one possible solution:

  1. Generate fake empty transactions for the target period

for example using CTE:

declare @StartDate datetime = '20170101'
declare @EndDate datetime  = '20171231'
;
with dt as
(
select @StartDate As 'thedate'
union all
select dateadd(month, 1, thedate) from dt where thedate < dateadd(month, -1, @EndDate)
) 
select 
    dt.thedate 'row date',
    datename(month,dt.thedate) 'Month', 
    YEAR(dt.thedate) 'Year',
    0 'Amount '
from dt
  1. Now you can add them to the transaction table (like union all) or you can do a left join with filtering on the result of your query.

I hope it helps!

答案 2 :(得分:0)

@Adam G,

感谢您的建议。我实际上从你的评论中得到了一个想法,而是创建了一个select语句来获得我需要的所有月份。在那之后,我加入了一个选择声明,在几个月匹配并且有效的情况下获取交易。见下文(来表名称已更改)

SELECT DISTINCT
    CNTRS_DATE_ENTITY.CALENDAR_MONTH
  , CNTRS_DATE_ENTITY.CNTRS_FIN_MONTH_POS
  , COALESCE (TRANS_DATA.TRANS_AMOUNT,0) AS TRANS_AMOUNT
FROM
    CNTRSINTDATA.DIM_CNTRS_DATE_ENTITY CNTRS_DATE_ENTITY 
LEFT JOIN 
    (
        SELECT
            QBS_TRANS_TSI.QB_NOMINAL_CODE
          , TO_CHAR(QBS_TRANS_TSI.QB_TRANS_DATE, 'Mon-YY') AS TRANS_MONTH
          , COALESCE (SUM(QBS_TRANS_TSI.QB_TRANS_AMOUNT),0) AS TRANS _AMOUNT
        FROM
            CNTRSINTDATA.FACT_QBS_TRANS_TSI QBS_TRANS_TSI
        WHERE 
            QBS_TRANS_TSI.TSI_NOMINAL_CODE = '6598'
        GROUP BY
            QBS_TRANS_TSI.QB_NOMINAL_CODE
          , TO_CHAR(QBS_TRANS_TSI.QB_TRANS_DATE, 'Mon-YY')
    ) TRANS_DATA
    ON TRANS_DATA.TRANS_MONTH = CNTRS_DATE_ENTITY.CALENDAR_MONTH

WHERE
    CNTRS_DATE_ENTITY.CNTRS_FIN_YEAR LIKE '2017'
ORDER BY
    CNTRS_DATE_ENTITY.CNTRS_FIN_MONTH_POS

然而,结果在所有月份都有,但在总和为零的实体列中有空白。有关补救措施的任何想法吗?