Subquery adalah pernyataan SELECT yang bersarang dalam kueri lain dan memungkinkan Anda mengkueri set hasil dari kueri tersebut. Kasus penggunaan umum mencakup menghitung nilai agregat, memeriksa keberadaan baris, memfilter data berdasarkan hasil kueri lain, melakukan pembaruan atau penghapusan berkorelasi, menyederhanakan operasi JOIN untuk mengembalikan satu nilai, menggunakan hasil sebagai tabel turunan untuk query luar, menyediakan dasar untuk pengurutan atau pengelompokan, serta melakukan perbandingan baris per baris. Topik ini menjelaskan jenis-jenis subquery yang didukung MaxCompute dan cara menggunakannya.
Fitur
MaxCompute mendukung jenis subquery berikut:
-
Subquery dasar digunakan dalam klausa
FROMsuatu kueri dan berperan sebagai tabel turunan. Anda dapat menggunakannya untuk perhitungan kompleks atau transformasi data dalam suatu kueri. -
Gunakan IN subquery dalam klausa
WHEREuntuk memilih baris dari query luar yang sesuai dengan kumpulan nilai yang dikembalikan oleh subquery. -
NOT IN subquery digunakan dalam klausa
WHEREuntuk menghapus baris dari query luar yang sesuai dengan set hasil subquery. -
EXISTS subquery menguji apakah subquery mengembalikan baris apa pun. Subquery ini berguna untuk memeriksa keberadaan baris terkait tanpa memerlukan data aktual yang dikandungnya.
-
NOT EXISTS subquery memilih baris dari query luar yang tidak memiliki kecocokan dalam subquery.
-
Scalar subquery mengembalikan satu nilai (satu baris dengan satu kolom). Subquery ini biasanya digunakan dalam daftar SELECT atau sebagai nilai kondisi dalam klausa
WHEREatauHAVING.
Pada waktu eksekusi, query optimizer sering mengonversi beberapa subquery—seperti scalar, IN, NOT IN, EXISTS, atau NOT EXISTS subquery—menjadi operasi JOIN. MAPJOIN adalah algoritma broadcast join yang efisien. Jika Anda menentukan bahwa hasil subquery merupakan tabel kecil, Anda dapat menambahkan petunjuk ke subquery tersebut untuk secara eksplisit menggunakan algoritma MAPJOIN. Untuk informasi lebih lanjut, lihat SUBQUERY_MAPJOIN HINT.
Data sampel
Contoh dalam topik ini menggunakan tabel sale_detail. Jalankan pernyataan berikut untuk membuat dan mengisinya:
-- Buat tabel partisi
CREATE TABLE IF NOT EXISTS sale_detail
(
shop_name STRING,
customer_id STRING,
total_price DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);
-- Tambahkan partisi
ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china') PARTITION (sale_date='2014', region='shanghai');
-- Masukkan data ke partisi 2013/china
INSERT INTO sale_detail PARTITION (sale_date='2013', region='china')
VALUES ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
-- Masukkan data ke partisi 2014/shanghai
INSERT INTO sale_detail PARTITION (sale_date='2014', region='shanghai')
VALUES ('null','c5',null),('s6','c6',100.4),('s7','c7',100.5);
Untuk memverifikasi data yang dimasukkan:
SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail;
Hasil:
+------------+-------------+-------------+------------+------------+
| shop_name | customer_id | total_price | sale_date | region |
+------------+-------------+-------------+------------+------------+
| s1 | c1 | 100.1 | 2013 | china |
| s2 | c2 | 100.2 | 2013 | china |
| s3 | c3 | 100.3 | 2013 | china |
| null | c5 | NULL | 2014 | shanghai |
| s6 | c6 | 100.4 | 2014 | shanghai |
| s7 | c7 | 100.5 | 2014 | shanghai |
+------------+-------------+-------------+------------+------------+
Mengkueri tabel partisi tanpa menentukan partisi memerlukan SET odps.sql.allow.fullscan=true; sebelum pernyataan tersebut. Di lingkungan produksi, tentukan partisi secara langsung untuk menghindari full table scan.
Subquery dasar
Kueri standar beroperasi pada tabel utama. Namun, kueri juga dapat beroperasi pada pernyataan select lain. Jenis kueri ini disebut subquery. Dalam klausa from, subquery dapat diperlakukan sebagai tabel dan digabungkan dengan tabel atau subquery lain menggunakan operasi join. Untuk informasi lebih lanjut tentang operasi join, lihat JOIN.
-
Sintaks
select <select_expr> from (<select_statement>) [<sq_alias_name>]; -
Parameter
-
select_expr: Wajib. Formatnya adalah
col1_name, col2_name, regular expression,..., yang menentukan kolom reguler, kolom kunci partisi, atau ekspresi reguler yang akan dikueri. -
select_statement: Wajib. Pernyataan subquery. Untuk informasi lebih lanjut tentang formatnya, lihat Sintaks SELECT.
-
sq_alias_name: Opsional. Alias untuk subquery.
-
table_name: Wajib. Nama tabel utama.
-
-
Contoh
-
Contoh 1: Perintah berikut memberikan contoh sintaks subquery dasar.
set odps.sql.allow.fullscan=true; select * from (select shop_name from sale_detail) a;Hasil:
+------------+ | shop_name | +------------+ | s1 | | s2 | | s3 | | null | | s6 | | s7 | +------------+
-
Contoh 2: Dalam klausa
from, subquery dapat diperlakukan sebagai tabel dan digunakan dalam operasijoindengan tabel atau subquery lain. Contoh perintahnya sebagai berikut.-- Buat tabel lalu lakukan operasi join. create table shop as select shop_name,customer_id,total_price from sale_detail; select a.shop_name, a.customer_id, a.total_price from (select * from shop) a join sale_detail on a.shop_name = sale_detail.shop_name;Hasil:
+------------+-----------------+-----------------+ | _c0 | scalarsubquery1 | scalarsubquery2 | +------------+-----------------+-----------------+ | null | c5 | NULL | | s6 | c6 | 100.4 | | s7 | c7 | 100.5 | | s1 | c1 | 100.1 | | s2 | c2 | 100.2 | | s3 | c3 | 100.3 | +------------+-----------------+-----------------+
-
In subquery
in subquery digunakan mirip dengan left semi join.
-
Sintaks
-
Format 1
select <select_expr1> from <table_name1> where <select_expr2> in (select <select_expr3> from <table_name2>); -- Pernyataan ini setara dengan pernyataan LEFT SEMI JOIN berikut. select <select_expr1> from <table_name1> <alias_name1> left semi join <table_name2> <alias_name2> on <alias_name1>.<select_expr2> = <alias_name2>.<select_expr3>;CatatanJika
select_expr2adalah kolom kunci partisi, subqueryselect <select_expr2> from <table_name2>dieksekusi dalam pekerjaan terpisah dan tidak dikonversi menjadisemi join. Hasil eksekusi kemudian dibandingkan denganselect_expr2. Partisi dalamtable_name1tidak dibaca jika nilaiselect_expr2-nya tidak ada dalam hasil yang dikembalikan. Hal ini memastikan bahwa partition pruning tetap efektif. -
Format 2
MaxCompute tidak hanya mendukung
in subquerytetapi juga kondisi berkorelasi. Klausawhere <table_name2_colname> = <table_name1>.<colname>dalam subquery merupakan kondisi berkorelasi. MaxCompute 1.0 tidak mendukung ekspresi yang mereferensikan baik tabel sumber dalam subquery maupun tabel sumber dalam query luar. MaxCompute 2.0 mendukung penggunaan ini, di mana kondisi filter ini menjadi bagian dari kondisiondalamsemi join.select <select_expr1> from <table_name1> where <select_expr2> in (select <select_expr3> from <table_name2> where <table_name1>.<col_name> = <table_name2>.<col_name>);CatatanMaxCompute mendukung
in subqueryyang tidak digunakan sebagai kondisijoin, misalnya jika berada di luar klausawhereatau berada dalam klausawheretetapi tidak dapat dikonversi menjadi kondisijoin. Dalam kasus ini, subquery tidak dapat dikonversi menjadisemi join, pekerjaan terpisah harus dijalankan untuk mengeksekusi subquery, dan kondisi berkorelasi tidak didukung. -
Format 3
Berdasarkan kemampuan di atas, MaxCompute kompatibel dengan dukungan PostgreSQL untuk multiple columns. Dibandingkan dengan membagi implementasi menjadi beberapa subquery, pendekatan ini mengurangi satu proses JOIN dan menghemat sumber daya komputasi. Penggunaan multi-kolom yang didukung adalah sebagai berikut:
-
Ekspresi yang mengikuti
indapat berupa pernyataan SELECT multi-kolom sederhana. -
Anda dapat menggunakan fungsi agregat dalam ekspresi yang mengikuti
in. Untuk informasi lebih lanjut, lihat Fungsi agregat. -
Ekspresi setelah
indapat berupa konstanta.
-
-
-
Parameter
-
select_expr1: Wajib. Formatnya adalah
col1_name, col2_name, regular expression,.... Parameter ini menentukan kolom reguler, kolom kunci partisi, atau ekspresi reguler yang akan dikueri. -
table_name1, table_name2: Wajib. Nama tabel.
-
select_expr2, select_expr3: Wajib. Nama kolom yang dipetakan dari table_name1 dan table_name2.
-
col_name: Wajib. Nama kolom.
-
-
Catatan penggunaan
Saat Anda menggunakan subquery dengan
IN, baris yang berisi nilai NULL secara otomatis dihapus dari set hasil subquery. -
Contoh
-
Contoh 1: Gunakan sintaks subquery Format 1.
set odps.sql.allow.fullscan=true; select * from sale_detail where total_price in (select total_price from shop);Hasil:
+-----------+-------------+-------------+-----------+--------+ | shop_name | customer_id | total_price | sale_date | region | +-----------+-------------+-------------+-----------+--------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | | s6 | c6 | 100.4 | 2014 | shanghai | | s7 | c7 | 100.5 | 2014 | shanghai | +-----------+-------------+-------------+-----------+--------+ -
Contoh 2: Gunakan sintaks subquery Format 2.
set odps.sql.allow.fullscan=true; select * from sale_detail where total_price in (select total_price from shop where customer_id = shop.customer_id);Hasil:
+-----------+-------------+-------------+-----------+--------+ | shop_name | customer_id | total_price | sale_date | region | +-----------+-------------+-------------+-----------+--------+ | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | | s6 | c6 | 100.4 | 2014 | shanghai | | s7 | c7 | 100.5 | 2014 | shanghai | +-----------+-------------+-------------+-----------+--------+ -
Contoh 3: Menggunakan pernyataan SELECT multi-kolom.
-- Untuk mempermudah pemahaman, data sampel dibuat ulang di sini. create table if not exists t1(a bigint,b bigint,c bigint,d bigint,e bigint); create table if not exists t2(a bigint,b bigint,c bigint,d bigint,e bigint); insert into table t1 values (1,3,2,1,1),(2,2,1,3,1),(3,1,1,1,1),(2,1,1,0,1),(1,1,1,0,1); insert into table t2 values (1,3,5,0,1),(2,2,3,1,1),(3,1,1,0,1),(2,1,1,0,1),(1,1,1,0,1); -- Skenario 1: Ekspresi setelah `in` adalah pernyataan SELECT multi-kolom sederhana. select a, b from t1 where (c, d) in (select a, b from t2 where e = t1.e); -- Hasil berikut dikembalikan. +------------+------------+ | a | b | +------------+------------+ | 1 | 3 | | 2 | 2 | | 3 | 1 | +------------+------------+ -- Skenario 2: Gunakan fungsi agregat dalam ekspresi setelah `in`. select a, b from t1 where (c, d) in (select max(a), b from t2 where e = t1.e group by b having max(a) > 0); -- Hasil berikut dikembalikan. +------------+------------+ | a | b | +------------+------------+ | 2 | 2 | +------------+------------+ -- Skenario 3: Ekspresi setelah `in` adalah konstanta. select a, b from t1 where (c, d) in ((1, 3), (1, 1)); -- Hasil berikut dikembalikan. +------------+------------+ | a | b | +------------+------------+ | 2 | 2 | | 3 | 1 | +------------+------------+
-
Not in subquery
not in subquery mirip dengan left anti join, tetapi keduanya tidak identik. Jika kolom yang ditentukan yang dikembalikan oleh subquery berisi nilai NULL apa pun, ekspresi not in dievaluasi sebagai NULL. Hal ini menyebabkan kondisi where gagal, dan tidak ada data yang dikembalikan. Ini berbeda dari left anti join.
-
Sintaks
-
Format 1
select <select_expr1> from <table_name1> where <select_expr2> not in (select <select_expr2> from <table_name2>); -- Pernyataan ini setara dengan pernyataan LEFT ANTI JOIN berikut. select <select_expr1> from <table_name1> <alias_name1> left anti join <table_name2> <alias_name2> on <alias_name1>.<select_expr1> = <alias_name2>.<select_expr2>;CatatanJika
select_expr2adalah kolom kunci partisi, subqueryselect <select_expr2> from <table_name2>dieksekusi dalam pekerjaan terpisah dan tidak dikonversi menjadianti join. Hasil eksekusi dibandingkan dengan nilaiselect_expr2. Partisi dalamtable_name1yang nilaiselect_expr2-nya tidak ada dalam set hasil yang dikembalikan tidak akan dibaca, sehingga memastikan partition pruning tetap efektif. -
Format 2
MaxCompute tidak hanya mendukung subquery
NOT INtetapi juga kondisi berkorelasi. Klausawhere <table_name2_colname> = <table_name1>.<colname>dalam subquery merupakan kondisi berkorelasi. MaxCompute 1.0 tidak mendukung ekspresi yang mereferensikan baik tabel sumber dalam subquery maupun tabel sumber query luar. MaxCompute 2.0 mendukung penggunaan ini. Kondisi filter ini merupakan bagian dari kondisiONdalamANTI JOIN.select <select_expr1> from <table_name1> where <select_expr2> not in (select <select_expr2> from <table_name2> where <table_name2_colname> = <table_name1>.<colname>);CatatanMaxCompute mendukung
not in subquerysaat tidak digunakan sebagai kondisijoin, seperti ketika muncul di luar klausawhereatau berada dalam klausawheretetapi tidak dapat dikonversi menjadi kondisijoin. Dalam kasus ini, subquery tidak dapat dikonversi menjadianti join. Pekerjaan terpisah harus diluncurkan untuk menjalankan subquery, dan kondisi berkorelasi tidak didukung. -
Format 3
Berdasarkan kemampuan di atas, MaxCompute kompatibel dengan dukungan PostgreSQL untuk multiple columns. Dibandingkan dengan membagi implementasi menjadi beberapa subquery, pendekatan ini mengurangi satu proses JOIN dan menghemat sumber daya komputasi. Penggunaan multi-kolom yang didukung adalah sebagai berikut:
-
Ekspresi setelah
not indapat berupa pernyataan SELECT yang mengembalikan multiple columns. -
Anda dapat menggunakan fungsi agregat dalam ekspresi yang mengikuti
not in. Untuk informasi lebih lanjut, lihat Fungsi agregat. -
Ekspresi yang mengikuti
not indapat berupa konstanta.
-
-
-
Parameter
-
select_expr1: Wajib. Formatnya adalah
col1_name, col2_name, regular expression,.... Parameter ini menentukan kolom reguler, kolom kunci partisi, atau ekspresi reguler yang akan dikueri. -
table_name1, table_name2: Wajib. Nama tabel.
-
select_expr2, select_expr3: Wajib. Nama kolom yang dipetakan dari table_name1 dan table_name2.
-
col_name: Wajib. Nama kolom.
-
-
Catatan penggunaan
Saat Anda menggunakan subquery dengan
NOT IN, baris yang berisi nilai NULL secara otomatis dihapus dari set hasil subquery. -
Contoh
-
Contoh 1: Gunakan sintaks subquery Format 1.
-- Buat tabel baru bernama shop1 dan masukkan data ke dalamnya. create table shop1 as select shop_name,customer_id,total_price from sale_detail; insert into shop1 values ('s8','c1',100.1); select * from shop1 where shop_name not in (select shop_name from sale_detail);Hasil:
+------------+-------------+-------------+ | shop_name | customer_id | total_price | +------------+-------------+-------------+ | s8 | c1 | 100.1 | +------------+-------------+-------------+ -
Contoh 2: Gunakan sintaks subquery Format 2.
set odps.sql.allow.fullscan=true; select * from shop1 where shop_name not in (select shop_name from sale_detail where customer_id = shop1.customer_id);Hasil:
+------------+-------------+-------------+ | shop_name | customer_id | total_price | +------------+-------------+-------------+ | s8 | c1 | 100.1 | +------------+-------------+-------------+ -
Contoh 3:
not in subquerytidak digunakan sebagai kondisijoin. Berikut contoh perintahnya.set odps.sql.allow.fullscan=true; select * from shop1 where shop_name not in (select shop_name from sale_detail) and total_price < 100.3;Karena klausa
whereberisiand, kueri tidak dapat dikonversi menjadianti joindan malah dieksekusi sebagai subquery dalam pekerjaan terpisah.Hasil:
+------------+-------------+-------------+ | shop_name | customer_id | total_price | +------------+-------------+-------------+ | s8 | c1 | 100.1 | +------------+-------------+-------------+ -
Contoh 4: Jika hasil subquery berisi nilai
NULL, tidak ada data yang dikembalikan. Perintah berikut memberikan contohnya.-- Buat tabel baru bernama sale dan masukkan data ke dalamnya. create table if not exists sale ( shop_name string, customer_id string, total_price double ) partitioned by (sale_date string, region string); alter table sale add partition (sale_date='2013', region='china'); insert into sale partition (sale_date='2013', region='china') values ('null','null',null),('s2','c2',100.2),('s3','c3',100.3),('s8','c8',100.8); set odps.sql.allow.fullscan=true; select * from sale where shop_name not in (select shop_name from sale_detail);Hasil:
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ +------------+-------------+-------------+------------+------------+ -
Contoh 5: Menggunakan pernyataan SELECT multi-kolom.
-- Untuk mempermudah pemahaman, data sampel dibuat ulang di sini. Data ini sama dengan data sampel di bagian IN subquery. create table if not exists t1(a bigint,b bigint,c bigint,d bigint,e bigint); create table if not exists t2(a bigint,b bigint,c bigint,d bigint,e bigint); insert into table t1 values (1,3,2,1,1),(2,2,1,3,1),(3,1,1,1,1),(2,1,1,0,1),(1,1,1,0,1); insert into table t2 values (1,3,5,0,1),(2,2,3,1,1),(3,1,1,0,1),(2,1,1,0,1),(1,1,1,0,1); -- Skenario 1: Ekspresi setelah `not in` adalah pernyataan SELECT multi-kolom sederhana. select a, b from t1 where (c, d) not in (select a, b from t2 where e = t1.e); -- Hasil berikut dikembalikan. +------------+------------+ | a | b | +------------+------------+ | 2 | 1 | | 1 | 1 | +------------+------------+ -- Skenario 2: Gunakan fungsi agregat dalam ekspresi setelah `not in`. select a, b from t1 where (c, d) not in (select max(a), b from t2 where e = t1.e group by b having max(a) > 0); -- Hasil berikut dikembalikan. +------------+------------+ | a | b | +------------+------------+ | 1 | 3 | | 3 | 1 | | 2 | 1 | | 1 | 1 | +------------+------------+ -- Skenario 3: Ekspresi setelah `not in` adalah konstanta. select a, b from t1 where (c, d) not in ((1, 3), (1, 1)); -- Hasil berikut dikembalikan. +------------+------------+ | a | b | +------------+------------+ | 1 | 3 | | 2 | 1 | | 1 | 1 | +------------+------------+
-
Exists subquery
Saat Anda menggunakan exists subquery, subquery tersebut mengembalikan True jika subquery memiliki setidaknya satu baris data, dan False jika tidak.
MaxCompute hanya mendukung subquery where yang berisi kondisi berkorelasi. exists subquery diimplementasikan sebagai left semi join.
-
Sintaks
select <select_expr> from <table_name1> where exists (select <select_expr> from <table_name2> where <table_name2_colname> = <table_name1>.<colname>); -
Parameter
-
select_expr: Wajib. Formatnya adalah
col1_name, col2_name, regular expression,..., yang menentukan kolom reguler, kolom kunci partisi, atau ekspresi reguler yang akan dikueri. -
table_name1, table_name2: Wajib. Nama tabel.
-
col_name: Wajib. Nama kolom.
-
-
Contoh
set odps.sql.allow.fullscan=true; select * from sale_detail where exists (select * from shop where customer_id = sale_detail.customer_id); -- Pernyataan ini setara dengan pernyataan berikut. select * from sale_detail a left semi join shop b on a.customer_id = b.customer_id;Hasil:
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ | null | c5 | NULL | 2014 | shanghai | | s6 | c6 | 100.4 | 2014 | shanghai | | s7 | c7 | 100.5 | 2014 | shanghai | | s1 | c1 | 100.1 | 2013 | china | | s2 | c2 | 100.2 | 2013 | china | | s3 | c3 | 100.3 | 2013 | china | +------------+-------------+-------------+------------+------------+
Not exists subquery
Saat Anda menggunakan not exists subquery, subquery tersebut mengembalikan True jika subquery tidak berisi data. Jika tidak, subquery mengembalikan False.
MaxCompute hanya mendukung subquery where yang berisi kondisi berkorelasi. not exists subquery diimplementasikan sebagai left anti join.
-
Sintaks
select <select_expr> from <table_name1> where not exists (select <select_expr> from <table_name2> where <table_name2_colname> = <table_name1>.<colname>); -
Parameter
-
select_expr: Wajib. Formatnya adalah
col1_name, col2_name, regular expression,..., yang menentukan kolom reguler, kolom kunci partisi, atau ekspresi reguler yang akan dikueri. -
table_name1, table_name2: Wajib. Nama tabel.
-
col_name: Wajib. Nama kolom.
-
-
Contoh
set odps.sql.allow.fullscan=true; select * from sale_detail where not exists (select * from shop where shop_name = sale_detail.shop_name); -- Pernyataan ini setara dengan pernyataan berikut. select * from sale_detail a left anti join shop b on a.shop_name = b.shop_name;Hasil:
+------------+-------------+-------------+------------+------------+ | shop_name | customer_id | total_price | sale_date | region | +------------+-------------+-------------+------------+------------+ +------------+-------------+-------------+------------+------------+
Scalar subquery
Jika subquery mengembalikan satu baris dan satu kolom, subquery tersebut dapat digunakan sebagai nilai skalar dalam operasi skalar. Jika kueri hanya mengembalikan satu baris, Anda dapat membungkus kueri tersebut dalam fungsi max atau min tanpa mengubah hasilnya. Scalar subquery juga mendukung penggunaan multi-kolom. Misalnya, scalar subquery dapat digunakan sebagai ekspresi multi-kolom dalam daftar SELECT, tetapi hanya ekspresi kesetaraan yang didukung. Scalar subquery juga dapat digunakan sebagai ekspresi BOOLEAN dalam daftar SELECT, tetapi hanya untuk perbandingan kesetaraan. Dalam klausa where, perbandingan multi-kolom didukung, tetapi hanya untuk kesetaraan.
-
Sintaks
-
Format 1
select <select_expr> from <table_name1> where (<select count(*) from <table_name2> where <table_name2_colname> = <table_name1>.<colname>) <scalar_operator> <scalar_value>; -- Pernyataan ini setara dengan pernyataan berikut. select <table_name1>.<select_expr> from <table_name1> left semi join (select <colname>, count(*) from <table_name2> group by <colname> having count(*) <scalar_operator> <scalar_value>) <table_name2> on <table_name1>.<colname> = <table_name2>.<colname>;Catatan-
Output dari
select count(*) from <table_name2> where <table_name2_colname> = <table_name1>.<colname>adalah set baris. Pernyataan ini hanya mengembalikan satu baris dan satu kolom. Oleh karena itu, dapat diperlakukan sebagai skalar. Namun, selama implementasi, pernyataan ini dikonversi menjadi operasijoinbila memungkinkan. -
Subquery hanya dapat digunakan sebagai skalar jika kompilator dapat memastikan pada waktu kompilasi bahwa subquery tersebut mengembalikan tepat satu baris dan satu kolom. Jika hal ini hanya dapat ditentukan pada waktu proses, kompilator akan mengembalikan error. Agar kompilator menerima pernyataan tersebut, dua syarat berikut harus dipenuhi:
-
Daftar
SELECTsubquery menggunakan fungsi agregat yang tidak berada dalam daftar parameter fungsi bernilai tabel. -
Subquery yang berisi fungsi agregat tidak memiliki klausa
group by.
-
-
-
Format 2
select (<select_statement>) from <table_name>;
-
-
Parameter
-
select_expr: Wajib. Formatnya adalah
col1_name, col2_name, regular expression,..., yang menentukan kolom reguler, kolom kunci partisi, atau ekspresi reguler yang akan dikueri. -
table_name1, table_name2: Wajib. Nama tabel.
-
col_name: Wajib. Nama kolom.
-
scalar_operator: Wajib. Misalnya, lebih besar dari (
>), lebih kecil dari (<), sama dengan (=), lebih besar dari atau sama dengan (>=), atau lebih kecil dari atau sama dengan (<=). -
scalar_value: Wajib. Nilai skalar.
-
select_statement: Wajib. Pernyataan subquery. Jika Anda menggunakan Format 2, subquery harus hanya mengembalikan satu baris. Untuk informasi lebih lanjut tentang formatnya, lihat Sintaks SELECT.
-
-
Batasan
-
scalar subquerydapat mereferensikan kolom dari query luar, tetapi ketika beberapa pernyataanscalar subquerybersarang, subquery hanya dapat mereferensikan kolom dari query luar langsungnya.-- Operasi yang diizinkan. select * from t1 where (select count(*) from t2 where t1.a = t2.a) = 3; -- Operasi yang tidak diizinkan. Subquery bersarang mereferensikan `t1.a`, yang berada dua level di luar, bukan dari layer luar langsungnya. select * from t1 where (select count(*) from t2 where (select count(*) from t3 where t3.a = t1.a) = 2) = 3;
-
-
Contoh
-
Contoh 1: Perintah berikut memberikan contoh kasus penggunaan umum.
set odps.sql.allow.fullscan=true; select * from shop where (select count(*) from sale_detail where sale_detail.shop_name = shop.shop_name) >= 1;Hasil:
+------------+-------------+-------------+ | shop_name | customer_id | total_price | +------------+-------------+-------------+ | s1 | c1 | 100.1 | | s2 | c2 | 100.2 | | s3 | c3 | 100.3 | | null | c5 | NULL | | s6 | c6 | 100.4 | | s7 | c7 | 100.5 | +------------+-------------+-------------+ -
Contoh 2: Menggunakan pernyataan SELECT multi-kolom.
-- Untuk mempermudah pemahaman, data sampel dibuat ulang di sini. create table if not exists ts(a bigint,b bigint,c double); create table if not exists t(a bigint,b bigint,c double); insert into table ts values (1,3,4.0),(1,3,3.0); insert into table t values (1,3,4.0),(1,3,5.0); -- Skenario 1: Kolom SELECT adalah ekspresi scalar subquery dengan multiple columns. Hanya ekspresi kesetaraan yang didukung. Penggunaan tidak valid: `select (select a, b from t where c > ts.c) as (a, b), a from ts;` select (select a, b from t where c = ts.c) as (a, b), a from ts; -- Hasil berikut dikembalikan. +------------+------------+------------+ | a | b | a2 | +------------+------------+------------+ | 1 | 3 | 1 | | NULL | NULL | 1 | +------------+------------+------------+ -- Skenario 2: Kolom SELECT adalah ekspresi Boolean. Hanya perbandingan kesetaraan yang didukung. Penggunaan tidak valid: `select (a,b) > (select a,b from ts where c = t.c) from t;` select (a,b) = (select a,b from ts where c = t.c) from t; -- Hasil berikut dikembalikan. +------+ | _c0 | +------+ | true | | false | +------+ -- Skenario 3: Klausa `where` mendukung perbandingan multi-kolom. Hanya perbandingan kesetaraan yang didukung. Penggunaan tidak valid: `select * from t where (a,b) > (select a,b from ts where c = t.c);` select * from t where c > 3.0 and (a,b) = (select a,b from ts where c = t.c); -- Hasil berikut dikembalikan. +------------+------------+------------+ | a | b | c | +------------+------------+------------+ | 1 | 3 | 4.0 | +------------+------------+------------+ select * from t where c > 3.0 or (a,b) = (select a,b from ts where c = t.c); -- Hasil berikut dikembalikan. +------------+------------+------------+ | a | b | c | +------------+------------+------------+ | 1 | 3 | 4.0 | | 1 | 3 | 5.0 | +------------+------------+------------+ -
Contoh 3: Menggunakan sintaks subquery Format 2.
set odps.sql.allow.fullscan=true; select (select * from sale_detail where shop_name='s1') from sale_detail;Hasil:
+------------+-----------------+-----------------+-----------------+-----------------+ | _c0 | scalarsubquery1 | scalarsubquery2 | scalarsubquery3 | scalarsubquery4 | +------------+-----------------+-----------------+-----------------+-----------------+ | s1 | c1 | 100.1 | 2013 | china | | s1 | c1 | 100.1 | 2013 | china | | s1 | c1 | 100.1 | 2013 | china | | s1 | c1 | 100.1 | 2013 | china | | s1 | c1 | 100.1 | 2013 | china | | s1 | c1 | 100.1 | 2013 | china | +------------+-----------------+-----------------+-----------------+-----------------+
-
Topik terkait
Penggunaan subquery yang berlebihan atau penulisan subquery yang tidak efisien dapat menurunkan performa kueri, terutama di lingkungan data besar. Untuk meningkatkan efisiensi kueri, pertimbangkan alternatif seperti tabel temporary, Tampilan yang di-materialisasi, atau merefaktor beberapa subquery menjadi operasi JOIN. Untuk informasi lebih lanjut, lihat Tampilan yang di-materialisasi dan JOIN.