2017-11-09 12 views
2

をcase文で凝集することができません:私は以下のようなデータを持っているハイブクエリで

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 | 
+-----------+----------------------------+ 

私はmerch_numことにより、簡単なクエリで、私はユニークcard_numを取得した場合にのみ以上1

を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つのクエリのみを書こうとするところに複数の条件があります。 case文、私は以下のようにそれを行うことができる午前使用:

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枚の以上のユニークなカードが存在しない、その商人のためとしてNULLとして2.49を作りたいが。ユニークなカードがNOの1以上が、その後、唯一私はcase文に適用された状態時に合計(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(mtrans.transaction_date、cdemo.date_birth)/ 365)<30 AND count(DISTINCT mtrans.card_num)> 1)THEN 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に基づいて取引金額のSUMを分類することができます。トリックは、サブクエリで上記のクエリを使用し、このサブクエリの結果を使用して分類することです。同じことをするためのクエリがここにあります。これはあなたの取引の数とトランザクションの合計を与える以下のように分類出力になり

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 | 
+-------------+----------+--------+------------+-----------+ 

、これはより多くのである私たちのデータセットです最終的な結果はそれ以下である。しかし、お客様の要件に応じて、1つ以上のユニークなカード(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 | 
+-------------+-------------------------+ 

これでほとんど完了です。これらの2つのテーブルを結合し、次に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 then TRUE ELSE FALSE END 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; 
関連する問題