2017-11-09 4 views
2

나는 데이터를 아래와 같이있다 :수없는

SELECT 
    mtrans.merch_num, 
    mtrans.card_num 
FROM a_sbp_db.merch_trans_daily mtrans 
INNER JOIN a_sbp_db.product_holding ph ON mtrans.card_num = ph.acc_num 
INNER JOIN a_sbp_db.cust_demo cdemo ON cdemo.cust_id = ph.cust_id 
WHERE mtrans.transaction_date LIKE '2017-09%' AND person_org_code='P' AND ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 30; 



+-----------+----------------------------+ 
| merch_num | card_num     | 
+-----------+----------------------------+ 
|   1 | 4658XXXXXXXXXXXXXXXXXXURMX | 
|   2 | 4658XXXXXXXXXXXXXXXXXXIE6X | 
|   2 | 4658XXXXXXXXXXXXXXXXXXDA8X | 
|   2 | 4658XXXXXXXXXXXXXXXXXX7D1X | 
|   2 | 4658XXXXXXXXXXXXXXXXXXTJ2X | 
|   2 | 4658XXXXXXXXXXXXXXXXXXQQWX | 
|   2 | 4659XXXXXXXXXXXXXXXXXXY4EX | 
|   2 | 4658XXXXXXXXXXXXXXXXXXRDOX | 
|   2 | 4658XXXXXXXXXXXXXXXXXX0O3X | 
|   2 | 4658XXXXXXXXXXXXXXXXXXNVBX | 
+-----------+----------------------------+ 

가 나는 간단한 쿼리에서 독특한 card_num 1보다

를 얻을 경우에만 merch_num에 의해 trans_amt를 집계 할 나는 그것을 할 수 있습니다 : 여기

SELECT 
    mtrans.merch_num, 
FROM_UNIXTIME(UNIX_TIMESTAMP(),'MMM-yyyy') AS process_month, 
SUM(mtrans.trans_amt) AS total_age_less_30_1 
FROM a_sbp_db.merch_trans_daily mtrans 
INNER JOIN a_sbp_db.product_holding ph ON mtrans.card_num = ph.acc_num 
INNER JOIN a_sbp_db.cust_demo cdemo ON cdemo.cust_id = ph.cust_id 
WHERE mtrans.transaction_date LIKE '2017-09%' AND person_org_code='P' AND ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 30 
GROUP BY 
    mtrans.merch_num having count(distinct mtrans.card_num) > 1; 

+-----------+---------------+---------------------+ 
| merch_num | process_month | total_age_less_30_1 | 
+-----------+---------------+---------------------+ 
|   2 | Nov-2017  | 2147.5    | 
+-----------+---------------+---------------------+ 

내가 상인 건너 뛸 수 있어요 - 5493036 그것을 고유 카드 1보다

을 가지고 있지 않는 한

하지만 복수 조건이 있습니다. &은 1 개의 쿼리 만 쓰고 싶습니다. 나는 아래처럼 할 수 있어요 사용하는 경우 문 :

나는 그 상인에 관해서는 2.49가 아니라 NULL 만들고 싶어
SELECT mtrans.merch_num, 
    FROM_UNIXTIME(UNIX_TIMESTAMP(),'MMM-yyyy') AS process_month, 
    NVL(SUM(CASE 
     WHEN (ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 30) 
      THEN mtrans.trans_amt ELSE 0 END), NULL) 
      AS total_age_less_30_1, 
    NVL(SUM(CASE 
     WHEN (ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) >= 30 
        AND ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 40) 
      THEN mtrans.trans_amt ELSE 0 END), NULL) 
      AS total_age_30_40_1 
FROM a_sbp_db.merch_trans_daily mtrans 
INNER JOIN a_sbp_db.product_holding ph ON mtrans.card_num = ph.acc_num 
INNER JOIN a_sbp_db.cust_demo cdemo ON cdemo.cust_id = ph.cust_id 
WHERE mtrans.transaction_date LIKE '2017-09%' 
    AND person_org_code='P' 
GROUP BY 
    mtrans.merch_num 

+-----------+---------------+---------------------+-------------------+ 
| merch_num | process_month | total_age_less_30_1 | total_age_30_40_1 | 
+-----------+---------------+---------------------+-------------------+ 
|  3 | Nov-2017  | 0     | 0     | 
|  4 | Nov-2017  | 0     | 0     | 
|  1 | Nov-2017  | 2.49    | 203.68   | 
|  2 | Nov-2017  | 2147.5    | 4907    | 
|  5 | Nov-2017  | 0     | 0     | 
+-----------+---------------+---------------------+-------------------+ 

, 1 개 이상의 독특한 카드가 존재하지 않습니다. 독특한 카드가 더 더 이상 1 만 나는 경우 문에 적용하고 조건이 때 합 (trans_amt)

를 표시 할 필요가없는 경우

내가 확인하는 조건을 가지고 적용 할 수없는 나는, 나는 오류가 아래 얻을 :

SELECT 
    mtrans.merch_num, 
    FROM_UNIXTIME(UNIX_TIMESTAMP(),'MMM-yyyy') AS process_month, 
    NVL(SUM(CASE 
     WHEN (ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 30 and count(distinct mtrans.card_num) > 1) 
      THEN mtrans.trans_amt ELSE 0 END), NULL) 
      AS total_age_less_30_1, 
    NVL(SUM(CASE 
     WHEN (ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) >= 30 
        AND  ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 40 and count(distinct mtrans.card_num) > 1) 
      THEN mtrans.trans_amt ELSE 0 END), NULL) 
      AS total_age_30_40_1     
FROM a_sbp_db.merch_trans_daily mtrans 
INNER JOIN a_sbp_db.product_holding ph ON mtrans.card_num = ph.acc_num 
INNER JOIN a_sbp_db.cust_demo cdemo ON cdemo.cust_id = ph.cust_id 
WHERE mtrans.transaction_date LIKE '2017-09%' 
    AND person_org_code='P' 
GROUP BY 
    mtrans.merch_num; 


ERROR: AnalysisException: aggregate function must not contain aggregate parameters: sum(CASE WHEN (round(datediff(mtrans.transaction_date, cdemo.date_birth)/365) < 30 AND count(DISTINCT mtrans.card_num) > 1) THEN mtrans.trans_amt ELSE 0 END) 

누군가 도움을 줄 수 있습니까?

+0

당신은'수 (distinct..' 또는 SUM''내 다른 집계 함수를 사용할 수 없습니다 SUM''의 인수를 외부를 사용하고 조건을 형성 –

답변

0

SUM 문 안에 개수가 있기 때문에 오류가있는 것 같습니다. 이것은 당신이 시도해야하는 것입니다, 어떻게 가는지 알려주세요 :

SELECT 
    mtrans.merch_num, 
    FROM_UNIXTIME(UNIX_TIMESTAMP(),'MMM-yyyy') AS process_month, 
    NVL(CASE 
     WHEN (ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 30 and count(distinct mtrans.card_num) > 1) 
      THEN SUM(mtrans.trans_amt) ELSE 0 END, NULL) 
      AS total_age_less_30_1, 
    NVL(CASE 
     WHEN (ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) >= 30 
        AND  ROUND(DATEDIFF(mtrans.transaction_date,cdemo.date_birth)/365) < 40 and count(distinct mtrans.card_num) > 1) 
      THEN SUM(mtrans.trans_amt) ELSE 0 END, NULL) 
      AS total_age_30_40_1     
FROM a_sbp_db.merch_trans_daily mtrans 
INNER JOIN a_sbp_db.product_holding ph ON mtrans.card_num = ph.acc_num 
INNER JOIN a_sbp_db.cust_demo cdemo ON cdemo.cust_id = ph.cust_id 
WHERE mtrans.transaction_date LIKE '2017-09%' 
    AND person_org_code='P' 
GROUP BY 
    mtrans.merch_num; 
+0

여전히 유사한 오류에 직면 : 오류 : AnalysisException : 집계 출력에 의해 생성되지 않은 목록 표현식을 선택하십시오 (GROUP BY 절에서 누락 된 경우) : nvl (CASE WHEN (dt mtrans.transaction_date, cdemo.date_birth)/365 <30 AND count (DISTINCT mtrans.card_num)> 1) 그 다음에 sum (mtrans.trans_amt) ELSE 0 END, NULL) –

0

나는 다음과 같이 더 좋은 방법으로 그것을 제안 할 것입니다.

(PS: I didn't have any hive access, so I am doing this using Postgresql using regular SQL. So, it should be easier to adapt to Hive SQL).

여기에 내 SQL 테이블과 레코드가 테이블에 삽입되었습니다.

CREATE TEMPORARY TABLE hivetest (
    merchant_id INTEGER, 
    card_number TEXT, 
    customer_dob TIMESTAMP, 
    transaction_dt TIMESTAMP, 
    transaction_amt DECIMAL 
); 

INSERT INTO hivetest VALUES 
(1, 'A', '1997-12-01', '2017-11-01', 10.0), 
(2, 'A', '1997-12-01', '2017-11-01', 11.0), 
(2, 'B', '1980-12-01', '2017-11-01', 12.0), 
(3, 'A', '1997-12-01', '2017-11-01', 13.0), 
(3, 'A', '1997-12-01', '2017-11-01', 14.0), 
(4, 'A', '1997-12-01', '2017-11-01', 15.0), 
(4, 'C', '1980-12-01', '2017-11-01', 16.0); 

먼저 테이블을 결합하고 transaction_age (transaction_dt - customer_dob을 제공하는 데이터 세트를 생성해야합니다. 이 단일 테이블에서 데이터 빼기를위한 대부분의 데이터가 있지만 간단한 INNER JOIN (s)을 사용하면 충분합니다. 어쨌든, 여기에 같은 검색어가 있습니다.

SELECT 
    merchant_id, card_number, DATE(customer_dob) customer_dob, DATE(transaction_dt) transaction_dt, 
    DATE_PART('year', DATE(transaction_dt)) - DATE_PART('year', DATE(customer_dob)) transaction_age, 
    transaction_amt 
FROM hivetest ORDER BY 1; 

이 결과는 다음과 같습니다.

+-------------+-------------+--------------+----------------+-----------------+----------------+ 
| merchant_id | card_number | customer_dob | transaction_dt | transaction_age |transaction_amt | 
+-------------+-------------+--------------+----------------+-----------------+----------------+ 
|   1 |  A  | 1997-12-01 | 2017-11-01  |    20 |   10.0 | 
|   2 |  A  | 1997-12-01 | 2017-11-01  |    20 |   11.0 | 
|   2 |  B  | 1980-12-01 | 2017-11-01  |    37 |   12.0 | 
|   3 |  A  | 1997-12-01 | 2017-11-01  |    20 |   13.0 | 
|   3 |  A  | 1997-12-01 | 2017-11-01  |    20 |   14.0 | 
|   4 |  A  | 1997-12-01 | 2017-11-01  |    20 |   15.0 | 
|   4 |  C  | 1980-12-01 | 2017-11-01  |    37 |   16.0 | 
+-------------+-------------+--------------+----------------+-----------------+----------------+ 

위의 데이터 세트는 당신이 원하는대로 당신이 transaction_age에 따라 거래 금액의 합을 분류 할 수 있습니다. 트릭은 하위 쿼리에서 위 쿼리를 사용하고이 하위 쿼리의 결과를 사용하여 분류하는 것입니다. 다음과 같은 쿼리를 수행합니다. 이것은 당신에게 거래의 수와 거래의 합계를 제공하는 아래와 같이 분류 출력 결과

SELECT 
    merchant_id, 
    -- Transaction Age less than 30 
    SUM(CASE WHEN transaction_age <= 30 THEN 1 ELSE 0 END) count_30, 
    SUM(CASE WHEN transaction_age <= 30 THEN transaction_amt ELSE 0 END) sum_30, 

    -- Transaction Age between 30 and 40 
    SUM(CASE WHEN transaction_age > 30 AND transaction_age <= 40 THEN 1 ELSE 0 END) case_30_40, 
    SUM(CASE WHEN transaction_age > 30 AND transaction_age <= 40 THEN transaction_amt ELSE 0 END) sum_30_40 
FROM 
(
    SELECT 
     merchant_id, transaction_amt, 
     DATE_PART('year', DATE(transaction_dt)) - DATE_PART('year', DATE(customer_dob)) transaction_age 
    FROM hivetest 
) m 
GROUP BY merchant_id ORDER BY 1; 

각 가맹점에 대한 각 범주에 대한 금액 : 이제

+-------------+----------+--------+------------+-----------+ 
| merchant_id | count_30 | sum_30 | case_30_40 | sum_30_40 | 
+-------------+----------+--------+------------+-----------+ 
|   1 |  1 | 10.0 |   0 |   0 | 
|   2 |  1 | 11.0 |   1 |  12.0 | 
|   3 |  2 | 27.0 |   0 |   0 | 
|   4 |  1 | 15.0 |   1 |  16.0 | 
+-------------+----------+--------+------------+-----------+ 

이 더 우리의 데이터 세트입니다 최종 결과는 더 적습니다. 그러나 귀하의 요구 사항에 따라 고유 한 카드가 두 개 이상인 판매자 (COUNT(DISTINCT card_number) > 1)에만 관심이 있습니다.

그래서 우리에게 이것을 제공하는 또 다른 쿼리를 작성할 수 있습니다. 아래는 이것을 계산하는 기준이며, 기준에 따라 우리는 해당 가맹점에 관심이 있는지 여부를 나타내는 플래그를 TRUE 또는 FALSE로 표시합니다.

SELECT 
    merchant_id, 
    CASE 
     WHEN COUNT(DISTINCT card_number) > 1 THEN 
      TRUE 
     ELSE 
      FALSE 
    END has_distinct_cards_gt_1 
FROM hivetest GROUP BY merchant_id ORDER BY 1 

다음과 같이 출력됩니다.

+-------------+-------------------------+ 
| merchant_id | has_distinct_cards_gt_1 | 
+-------------+-------------------------+ 
|   1 |     false | 
|   2 |     true | 
|   3 |     false | 
|   4 |     true | 
+-------------+-------------------------+ 

이제 거의 완료되었습니다. 이 두 테이블을 조인 한 다음 has_distinct_cards_gt_1을 기반으로하면 이전에 생성 된 데이터 세트의 열을 적절하게 표시하면됩니다.

여기에 최종 결합 쿼리와 결과 집합 데이터가 생성됩니다.

SELECT 
    merchants_all.merchant_id, 

    -- Age < 30 
    CASE 
     WHEN merchants_cards.has_distinct_cards_gt_1 THEN 
      sum_30 
     ELSE 
      0 
    END total_sum_30, 

    -- Age in 30 and 40 
    CASE 
     WHEN merchants_cards.has_distinct_cards_gt_1 THEN 
      sum_30_40 
     ELSE 
      0 
    END total_sum_30_40 
FROM 
    (
     SELECT 
      merchant_id, 
      SUM(CASE WHEN transaction_age <= 30 THEN transaction_amt ELSE 0 END) sum_30, 
      SUM(CASE WHEN transaction_age > 30 AND transaction_age <= 40 THEN transaction_amt ELSE 0 END) sum_30_40 
     FROM 
     ( 
      SELECT merchant_id, DATE_PART('year', DATE(transaction_dt)) - DATE_PART('year', DATE(customer_dob)) transaction_age, transaction_amt 
      FROM hivetest 
    ) m 
     GROUP BY merchant_id 
) merchants_all 
JOIN 
    (
    SELECT merchant_id, CASE WHEN COUNT(DISTINCT card_number) > 1 THEN TRUE ELSE FALSE END has_distinct_cards_gt_1 
    FROM hivetest GROUP BY merchant_id ORDER BY 1 
) merchants_cards 
ON 
(merchants_all.merchant_id = merchants_cards.merchant_id); 

그리고 이렇게하면 필요한 최종 데이터가 생성됩니다.

+-------------+--------------+-----------------+ 
| merchant_id | total_sum_30 | total_sum_30_40 | 
+-------------+--------------+-----------------+ 
|   1 |   0 |    0 | 
|   2 |   11.0 |   12.0 | 
|   3 |   0 |    0 | 
|   4 |   15.0 |   16.0 | 
+-------------+--------------+-----------------+ 

이 정보가 도움이되는지 알려주세요.

+0

Deepak, 도움을 주셔서 감사합니다.하지만 고유 한 카드 번호도 이전과는 다를 수 있습니다. 아래 검색어는 글로벌 가맹점 수준의 고유 카드를 제공하며 나이가 지켜야합니다. 선택 merchant_id, 사례 언제 (DISTINCT card_number)> 1 그 다음 TRUE ELSE 거짓 끝 has_distinct_cards_gt_1 FROM hivetest GROUP BY merchant_id ORDER BY 1 –

0

SUM 내부의 COUNT가 문제입니다. 여기 해결책이 있습니다. 나는 그것을 시험하지 않았다. person_org_code 테이블이 속한 것이 분명하지 않습니다. 그것이 merch_trans_daily에 있으면 person_org_code = 'P'를 뷰의 where 절에 추가하십시오. 그것이 효과가 있는지 알자! ..

WITH mtrans_count AS 
(SELECT merch_num, 
     COUNT(1) AS cnt 
    FROM a_sbp_db.merch_trans_daily 
    WHERE mtrans.transaction_date LIKE '2017-09%' 
) 
SELECT mtrans.merch_num 
    ,FROM_UNIXTIME(UNIX_TIMESTAMP(), 'MMM-yyyy') AS process_month 
    ,NVL(SUM(CASE 
       WHEN (
         ROUND(DATEDIFF(mtrans.transaction_date, cdemo.date_birth)/365) < 30 
         AND mtrans_count.cnt > 1 
         ) 
        THEN mtrans.trans_amt 
       ELSE 0 
       END), NULL) AS total_age_less_30_1 
    ,NVL(SUM(CASE 
       WHEN (
         ROUND(DATEDIFF(mtrans.transaction_date, cdemo.date_birth)/365) >= 30 
         AND ROUND(DATEDIFF(mtrans.transaction_date, cdemo.date_birth)/365) < 40 
         AND mtrans_count.cnt > 1 
         ) 
        THEN mtrans.trans_amt 
       ELSE 0 
       END), NULL) AS total_age_30_40_1 
FROM a_sbp_db.merch_trans_daily mtrans 
INNER JOIN a_sbp_db.product_holding ph ON mtrans.card_num = ph.acc_num 
INNER JOIN a_sbp_db.cust_demo cdemo ON cdemo.cust_id = ph.cust_id 
INNER JOIN mtrans_count ON mtrans_count.merch_num = mtrans.merch_num 
WHERE mtrans.transaction_date LIKE '2017-09%' 
    AND person_org_code = 'P' 
GROUP BY mtrans.merch_num;