2016-12-03 35 views
0

クエリをレガシーからスタンダードSQLに移行したところで、ネストされたデータと配列を処理する方法を学習しました。エラー:2つ以上の要素がスカラーサブクエリで生成されました

基本的に私たちが何をしたいのかga_sessions表から以下のデータを取得することです。そうするには

visitor id, session id, array of skus 
visitor 1, session 1, [sku_0, sku_1, (...), sku_n] 
visitor 1, session 2, [skus] 

我々はこの単純なクエリ実行:

WITH 
    customers_data AS(
    SELECT 
    fullvisitorid fv, 
    visitid v, 
    ARRAY_AGG((
     SELECT 
     prods.productsku 
     FROM 
     UNNEST(hits.product) prods)) sku 
    FROM 
    `dataset_id.ga_sessions_*`, 
    UNNEST(hits) hits 
    WHERE 
    1 = 1 
    AND _table_suffix BETWEEN FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) 
    AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 0 DAY)) 
    --and (select count(productsku) from unnest(hits.product) where productsku is not null) = 1 
    GROUP BY 
    fv, 
    v 
    LIMIT 
    100) 
SELECT 
    * 
FROM 
    customers_data 

をしかし、我々はこのエラーを取得:

Error: Scalar subquery produced more than one element 

hitsフィールドのデータはそうですこのようmething:

enter image description here

をだから我々はwhere句バックadddedとき:それがエラーを与えるものではありません

and (select count(productsku) from unnest(hits.product) where productsku is not null) = 1 

をしかし結果はSKUを重複していると我々はまた、より大きな内部のSKUを失いましたアレイ。

質問が間違っていて、配列がネストされないようにしていますか?

答えて

3

私が正しく理解していれば、私はあなたがこのような何かをしたいと思う:

WITH customers_data AS (
    SELECT 
    fullvisitorid fv, 
    visitid v, 
    ARRAY_CONCAT_AGG(ARRAY(
     SELECT productsku FROM UNNEST(hits.product))) sku 
    FROM 
    `dataset_id.ga_sessions_*`, 
    UNNEST(hits) hits 
    WHERE 
    _table_suffix BETWEEN 
     FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)) 
     AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE(), INTERVAL 0 DAY)) 
    GROUP BY 
    fv, 
    v 
    LIMIT 
    100 
) 
SELECT 
    * 
FROM 
    customers_data; 

これは、行ごとのSKUを抽出ARRAYサブクエリを超えるARRAY_CONCAT_AGGを使用してのSKUのすべてを保持します。

SELECT * 
    REPLACE (ARRAY(SELECT DISTINCT s FROM UNNEST(sku) AS s) AS sku) 
FROM 
    customers_data; 

編集:あなたは、行全体でのSKUの全てを重複排除したい場合は、と

SELECT 
    * 
FROM 
    customers_data; 

を置き換えることができ、より読書のために、ドキュメントのtypes of expression subqueriesを見てみましょう。あなたのケースでは、ARRAYサブクエリが必要でした。なぜなら、各行にARRAY<STRUCT<...>>を入れて、フィールドタイプのARRAYに変換して、行間で配列を連結することだったからです。

ARRAY_AGGは個々の要素から配列を作成しますが、ARRAY_CONCAT_AGGは配列の連結から配列を作成します。それらの違いは、配列リテラルコンストラクタ[]ARRAY_CONCATの違いと似ていますが、_AGGのバージョンは集合関数です。

スタンドアロンの例として、次の試みることができる:

WITH T AS (
    SELECT ARRAY<STRUCT<x INT64, y INT64>>[(1, 10), (2, 11), (3, 12)] AS arr UNION ALL 
    SELECT ARRAY<STRUCT<x INT64, y INT64>>[(4, 13)] UNION ALL 
    SELECT ARRAY<STRUCT<x INT64, y INT64>>[(5, 14), (6, 15)] 
) 
SELECT ARRAY(SELECT x FROM UNNEST(arr)) AS x_array 
FROM T; 

これは、各配列内の要素はarrの各要素からx分野のものであるカラムx_arrayを返します。結果に単一の行が存在するようにすべての配列を連結するには、ARRAY_CONCAT_AGGを使用します。:あなたの他の質問については

WITH T AS (
    SELECT ARRAY<STRUCT<x INT64, y INT64>>[(1, 10), (2, 11), (3, 12)] AS arr UNION ALL 
    SELECT ARRAY<STRUCT<x INT64, y INT64>>[(4, 13)] UNION ALL 
    SELECT ARRAY<STRUCT<x INT64, y INT64>>[(5, 14), (6, 15)] 
) 
SELECT ARRAY_CONCAT_AGG(ARRAY(SELECT x FROM UNNEST(arr))) AS x_array 
FROM T; 

は、REPLACEは、それらが交換するために意図されている列とペアになっ式のリストを受け付けます。式はリテラルのような単純なものでもよいし、ARRAYサブクエリーのようなもっと複雑なものでもかまいません。たとえば:

WITH T AS (
    SELECT 1 AS x, 'foo' AS y, true AS z UNION ALL 
    SELECT 2, 'bar', false UNION ALL 
    SELECT 3, 'baz', true 
) 
SELECT * REPLACE(1 - x AS x, CAST(x AS STRING) AS y) 
FROM T; 

これは1 - x、代わりにCAST(x AS STRING)の結果とSELECT *から返されたであろうオリジナルxy列を置き換えます。

+0

エリオットのお手伝いをしてくれてありがとう!出来た!私たちが以前にしたことが間違っていた理由を説明してください。フィールド 'productsku'をネストしてから' array_agg'を使うとうまくいかないでしょうか?なぜそれを 'array'にキャストする必要があるのでしょうか?また、 'select * replace'構文について説明してください。私はそれについてのドキュメントを読んだが、このクエリでどのように動作しているのか分からなかった。もう一度、ありがとう! –

+0

私はコメントを書き始めましたが、十分なスペースがなかったので、答えを更新しました。トピックに関する詳細を知りたい場合は、別の質問を投稿してください。ありがとう! –

+0

うーん、私はそれを参照してください!今私は、私が間違ったことを理解しています。エリオット助けてくれてありがとう! –

関連する問題