[解決済み] SQLの配列の平坦化。なぜCROSS JOIN UNNESTは、入れ子になっているすべての値とすべての行を結合しないのですか?
質問
この質問は特定の問題を解決するためではなく、配列を平坦化するために使われる一般的なSQLイディオムの舞台裏で実際に何が起こっているかを理解するためのものです。 舞台裏には何らかのマジックがあり、私は構文上の砂糖のカーテンの裏側を覗いて、何が起こっているのか見てみたいのです。
次のようなテーブルを考えてみましょう。
t1
:
という関数があるとします。
FLATTEN
は、配列型のカラムを受け取ってそのカラム内の各配列を展開し、各配列の各値に対して一行ずつになるようにします。
SELECT FLATTEN(numbers_array) AS flattened_numbers FROM t1
と呼ぶことにします。
t2
SQLでは、CROSS JOINは2つのテーブルの行を結合し、最初のテーブルの各行と2番目のテーブルの各行を結合します。ですから、もし私たちが
SELECT id, flattened.flattened_numbers from t1 CROSS JOIN flattened
となります。
さて、flattenは単なる想像上の関数で、CROSS JOINと組み合わせても、ご覧のように、元の値のそれぞれは
id
列と混在することになります。
flattened_numbers
を元の行のそれぞれから取得します。 がないため、すべてが混ざり合ってしまいます。
WHERE
の行だけを選択する節があります。
CROSS JOIN
となります。
実際に配列を平らにするために使われるパターンは、次のようなものです。
SELECT id, flattened_numbers FROM t1 CROSS JOIN UNNEST(sequences.some_numbers) AS flattened_numbers
を生成します。
しかし、なぜ
CROSS JOIN UNNEST
のパターンが実際に機能します。 なぜなら
CROSS JOIN
が含まれていないため
WHERE
節と同じように動作することを期待します。
FLATTEN
関数を使用すると、非ネストの値がすべて
t1
.
の中で実際に何が起こっているのか、誰か「解きほぐす」ことができますか?
CROSS JOIN UNNEST
このパターンでは、各行がそれ自身のネストされた値のみと結合されるようにします (他の行のネストされた値とは結合されません)。
どのように解決するのですか?
これを考えるには、行単位で何が起こっているかを見るのが一番です。入力データをいくつか設定します。
WITH t1 AS (
SELECT 1 AS id, [0, 1] AS numbers_array UNION ALL
SELECT 2, [2, 4, 5]
)
...
(2行目に3つ目の要素を使って面白くしています)。そこから選択するだけなら、次のような出力が得られます。
WITH t1 AS (
SELECT 1 AS id, [0, 1] AS numbers_array UNION ALL
SELECT 2, [2, 4, 5]
)
SELECT * FROM t1;
+----+---------------+
| id | numbers_array |
+----+---------------+
| 1 | [0, 1] |
| 2 | [2, 4, 5] |
+----+---------------+
では、アンネストについて説明します。その
UNNEST
関数は、配列を受け取り、その配列の要素型の値テーブルを返します。BigQuery のテーブルの多くは列の集まりとして定義された SQL テーブルですが、値テーブルの行はいくつかの
値
という型があります。については
numbers_array
,
UNNEST(numbers_array)
の値テーブルを返します。
INT64
というのは
numbers_array
は配列で、要素タイプは
INT64
. この値表には
numbers_array
から現在の行に対して
t1
.
を持つ行に対して
id
が返す値テーブルの内容は、1である。
UNNEST(numbers_array)
があります。
+-----+
| f0_ |
+-----+
| 0 |
| 1 |
+-----+
これは、次のクエリで得られるものと同じです。
SELECT * FROM UNNEST([0, 1]);
UNNEST([0, 1])
この場合、quot; から値テーブルを作成することを意味します。
INT64
値
0
と
1
となります。
同様に
id
が 2 である場合,値テーブルの内容は
UNNEST(numbers_array)
があります。
+-----+
| f0_ |
+-----+
| 2 |
| 4 |
| 5 |
+-----+
では、どのように
CROSS JOIN
がフィットします。ほとんどの場合
CROSS JOIN
相関のない2つのテーブルの間。つまり、右側のテーブルの中身が
CROSS JOIN
は、左側のテーブルの現在の内容によって定義されるものではありません。
配列の場合や
UNNEST
によって生成される値表の内容です。
UNNEST(numbers_array)
の現在の行によって変化します。
t1
. 2 つのテーブルを結合すると、現在の行のクロスプロダクトが
t1
のすべての行と
UNNEST(numbers_array)
. 例えば
WITH t1 AS (
SELECT 1 AS id, [0, 1] AS numbers_array UNION ALL
SELECT 2, [2, 4, 5]
)
SELECT id, number
FROM t1
CROSS JOIN UNNEST(numbers_array) AS number;
+----+--------+
| id | number |
+----+--------+
| 1 | 0 |
| 1 | 1 |
| 2 | 2 |
| 2 | 4 |
| 2 | 5 |
+----+--------+
numbers_array
は1行目に2つの要素、2行目に3つの要素を持つので
2 + 3 = 5
の行がクエリの結果に含まれます。
を平坦化することとどう違うのかという質問に答えます。
numbers_array
と
では
を実行する
CROSS JOIN
このクエリの結果を見てみましょう。
WITH t1 AS (
SELECT 1 AS id, [0, 1] AS numbers_array UNION ALL
SELECT 2, [2, 4, 5]
), t2 AS (
SELECT number
FROM t1
CROSS JOIN UNNEST(numbers_array) AS number
)
SELECT number
FROM t2;
+--------+
| number |
+--------+
| 0 |
| 1 |
| 2 |
| 4 |
| 5 |
+--------+
この場合
t2
という名前のカラムを持つSQLテーブルです。
number
をそれらの値で指定します。を実行すると
CROSS JOIN
との間に
t1
と
t2
とすると、すべての行の真のクロスプロダクトが得られます。
WITH t1 AS (
SELECT 1 AS id, [0, 1] AS numbers_array UNION ALL
SELECT 2, [2, 4, 5]
), t2 AS (
SELECT number
FROM t1
CROSS JOIN UNNEST(numbers_array) AS number
)
SELECT id, numbers_array, number
FROM t1
CROSS JOIN t2;
+----+---------------+--------+
| id | numbers_array | number |
+----+---------------+--------+
| 1 | [0, 1] | 0 |
| 1 | [0, 1] | 1 |
| 1 | [0, 1] | 2 |
| 1 | [0, 1] | 4 |
| 1 | [0, 1] | 5 |
| 2 | [2, 4, 5] | 0 |
| 2 | [2, 4, 5] | 1 |
| 2 | [2, 4, 5] | 2 |
| 2 | [2, 4, 5] | 4 |
| 2 | [2, 4, 5] | 5 |
+----+---------------+--------+
では、先ほどのクエリと何が違うかというと
CROSS JOIN UNNEST(numbers_array)
? この場合
t2
から各行ごとに変更されることはありません。
t1
. の最初の行は
t1
には5つの行があります。
t2
. の2行目については
t1
には5つの行があります。
t2
. その結果
CROSS JOIN
を返します。
5 + 5 = 10
行の合計です。
関連
-
[解決済み】使用されるSELECT文は列の数が異なる(REDUX!)
-
[解決済み] SELECT DISTINCTを指定した場合、ORDER BY項目は必ず選択リストに表示されます。
-
[解決済み] 集計を行わずに行から列へピボット移動する
-
[解決済み] 各GROUP BYグループの最初の行を選択しますか?
-
[解決済み] SQL ServerでJOINを使用してUPDATE文を実行するにはどうすればよいですか?
-
[解決済み] 最初の行への結合方法
-
[解決済み] SQL Serverでレコードを削除した後、IDシードをリセットする。
-
[解決済み] SQL Server テーブルからランダムな n 行を選択する
-
[解決済み】SQL Serverで既存のテーブルにデフォルト値を持つカラムを追加する
-
[解決済み] SQL ServerでINNER JOINを使用して削除するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】CREATE VIEW は、バッチ内の唯一のステートメントでなければなりません。
-
[解決済み】2つの列を分割する方法は?
-
[解決済み] varchar 値 'simple, ' をデータ型 int に変換する際に変換に失敗しました。
-
[解決済み】ORA-01791: SELECTされた式ではない
-
[解決済み] WHERE x IN (5) vs WHERE x = 5 ...なぜINを使うのか?
-
[解決済み] SQL Server - 'RETURN'付近の、条件が想定されるコンテキストで指定された、非ブール型の式。
-
[解決済み] エラー: 名前解析スクリプトで正しい関数に渡された長さのパラメーターが無効です。
-
[解決済み] SQLクエリで2つの列から値を引き算する
-
[解決済み] Presto SQL ピボッティング(言葉は悪いですが)データ
-
[解決済み] VBA - ADODB.CommandTextの実行