【问题标题】:SQL: count accounts with certain transaction ID present in each of past 3 monthsSQL:统计过去 3 个月中每个月存在特定交易 ID 的账户
【发布时间】:2017-05-03 03:40:24
【问题描述】:

我有一个 SQL 脚本,用于计算给定月份中具有特定事务 ID 的帐户数。我想对此进行修改,以便仅在过去 3 个月的每个月中放置这些类型的交易时才计算帐户数,而不仅仅是在任何给定的月份。这是为了过滤掉一次性事件。

我对 SQL 还很陌生,并且无法通过我所做的搜索找到明确的答案。将不胜感激任何帮助。谢谢!

SELECT
   CLDR.YEAR_MONTH
  ,COUNT(DISTINCT TRAN.ACCT_NBR) AS IC_DD --counts all unique Acct numbers

FROM
   REPORTS.FINANCIAL_TRAN AS TRAN

INNER JOIN REPORTS.ACCT AS ACCT ON TRAN.ACCT_NBR=ACCT.ACCT_NBR
INNER JOIN REPORTS.DATE AS CLDR ON TRAN.TRAN_DT=CLDR.CALENDAR_DATE

WHERE
   TRAN.TRAN_CD IN ('id1','id2','id3')  --Filters on Transaction IDs
 AND
   TRAN.TRAN_DT BETWEEN '2017-01-01' AND '2017-03-31'

GROUP BY
   CLDR.YEAR_MONTH

ORDER BY
   CLDR.YEAR_MONTH

【问题讨论】:

    标签: sql teradata


    【解决方案1】:

    您无需同时加入ACCT 和日历表:

    SELECT Count(*)
    FROM
     (
       SELECT ACCT_NBR
       FROM REPORTS.FINANCIAL_TRAN AS TRAN
       WHERE
          TRAN.TRAN_CD IN ('id1','id2','id3')  --Filters on Transaction IDs
        AND
          TRAN.TRAN_DT BETWEEN '2017-01-01' AND '2017-03-31'
       GROUP BY ACCT_NBR
       -- rows for all three months exist for this account 
       HAVING Count(DISTINCT EXTRACT(MONTH FROM tran_dt)) = 3
     ) AS dt
    

    编辑:

    根据 cmets,这不应该在固定的月份范围内进行,而是动态进行,即计算每个月有多少帐户在前两个月内也有交易?

    SELECT trans_month, Count(*)
    FROM
     (
       SELECT
          ACCT_NBR,
         ,Trunc(TRAN_DT, 'mon') AS trans_month -- 1st of month
       FROM TRAN
       WHERE
          TRAN.TRAN_CD IN ('id1','id2','id3')  --Filters on Transaction IDs
    --    AND
    --      TRAN.TRAN_DT BETWEEN '2017-01-01' AND '2017-03-31'
       GROUP BY ACCT_NBR, trans_month -- distinct list first
       QUALIFY 
          -- check if there are three consecutive months
          -- e.g. 
          -- 2017-02-01 <- 2 preceding, must be 2 months before current row
          -- 2017-03-01 <- 1 preceding
          -- 2017-04-01 <- current row
          Min(trans_month)
          Over (PARTITION BY ACCT_NBR
                ORDER BY trans_month
                ROWS 2 Preceding) = Add_Months(trans_month,-2)
     ) AS dt
    GROUP BY trans_month
    ORDER BY trans_month
    

    【讨论】:

    • 成功了。我只是想办法让它在数据拉取中也显示日历结果。谢谢!
    • @starfly:什么日历结果,DATE '2017-01-01'?您有一个硬编码的日期范围,并且您想统计每个月的行数
    • 我想有一个格式为 YYYYMM 的日期列(这就是我加入 CLDR 的原因),然后达到一个点,对于任何给定的月份,它都会为 TRAN_DT 提取最后 3 个月。所以如果CLDR月份是201703,拉TRAN_DT 2017-01-01 - 2017-03-31;如果 CLDR 月份是 201702,则拉取 TRAN_DT 2016-12-01 - 2017-02-28。有没有直接的方法?
    • @starfly:您的示例基于三个月的已知范围,如果您想动态进行此计算,方法将完全不同。
    • 感谢您添加编辑。非常有帮助和教育,非常感谢!
    【解决方案2】:

    蛮力方法是为每个月添加一个IN 子句:

    AND TRAN.ACCT_NBR IN (
           SELECT ACCT_NBR 
           FROM REPORTS.FINANCIAL_TRAN 
           WHERE TRAN_DT BETWEEN '2017-01-01' AND '2017-01-31')
    AND TRAN.ACCT_NBR IN (
           SELECT ACCT_NBR 
           FROM REPORTS.FINANCIAL_TRAN 
           WHERE TRAN_DT BETWEEN '2017-02-01' AND '2017-02-28')
    AND TRAN.ACCT_NBR IN (
           SELECT ACCT_NBR 
           FROM REPORTS.FINANCIAL_TRAN 
           WHERE TRAN_DT BETWEEN '2017-03-01' AND '2017-03-31')
    

    【讨论】:

    • 这将成为 WHERE 子句的一部分,对吗?我会试试这个,看看它是否能得到我想要的结果。
    【解决方案3】:

    这是我在 MSSQL 中的做法。我很确定您在 Teradata 中具有窗口功能。

    我正在为我的测试示例简化您的数据,但这应该会让您走上正轨。 CTE 的原因是您不能在窗口函数中使用 COUNT DISTINCT。

    CREATE TABLE #Test (
         ACCT_NBR int
        ,YEAR_MONTH char(5)
        ,TRAN_DT datetime )
    
    INSERT INTO #Test
    SELECT 123, '17/01', '2017-01-11';
    INSERT INTO #Test
    SELECT 123, '17/02', '2017-02-12';
    INSERT INTO #Test
    SELECT 123, '17/02', '2017-02-21';
    INSERT INTO #Test
    SELECT 123, '17/03', '2017-03-19';
    INSERT INTO #Test
    SELECT 356, '17/01', '2017-01-14';
    INSERT INTO #Test
    SELECT 356, '17/01', '2017-01-22';
    INSERT INTO #Test
    SELECT 356, '17/03', '2017-03-14';
    
    SELECT * FROM #Test;
    
    WITH CTE AS (
        SELECT DISTINCT
             ACCT_NBR AS AccountNumber
            ,YEAR_MONTH AS YYMM
        FROM #Test
        WHERE TRAN_DT BETWEEN '2017-01-01' AND '2017-03-31' )
    
    SELECT DISTINCT
         YYMM
        ,COUNT(AccountNumber) OVER (PARTITION BY YYMM ) AS Counts
    FROM CTE
    

    【讨论】:

    • 谢谢。不幸的是,我没有对 DBMS 的写入权限,因此无法创建(临时)表。
    • 然后使用表变量。或者请求许可。或者只是访问 user7593937 只是向您展示一个示例并且您可以使用您的表的事实。
    • 临时表只是为了给我一些可以使用的数据,尝试复制您正在使用的数据——该解决方案不需要临时表。只需在 CTE 中使用您的查询,然后使用窗口函数进行计数。
    猜你喜欢
    • 2019-03-03
    • 2013-09-16
    • 1970-01-01
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    相关资源
    最近更新 更多