Bagian 1 - Bergabung dan Serikat Pekerja
Jawaban ini mencakup:
- Bagian 1
- Bergabung dengan dua atau lebih tabel menggunakan gabungan dalam (Lihat entri wikipedia untuk info tambahan)
- Cara menggunakan kueri gabungan
- Gabungan Luar Kiri dan Kanan ( jawaban stackOverflow ini sangat bagus untuk menggambarkan tipe gabungan)
- Quers intersectect (dan bagaimana mereproduksi mereka jika database Anda tidak mendukung mereka) - ini adalah fungsi dari SQL-Server ( lihat info ) dan bagian dari alasan saya menulis semua ini di tempat pertama.
- Bagian 2
- Subqueries - apa itu, di mana mereka dapat digunakan dan apa yang harus diperhatikan
- Cartesian bergabung dengan AKA - Oh, kesengsaraan!
Ada sejumlah cara untuk mengambil data dari beberapa tabel dalam database. Dalam jawaban ini, saya akan menggunakan sintaks join ANSI-92. Ini mungkin berbeda dengan sejumlah tutorial lain di luar sana yang menggunakan sintaks ANSI-89 yang lebih lama (dan jika Anda terbiasa dengan 89, mungkin tampak jauh kurang intuitif - tetapi yang bisa saya katakan adalah mencobanya) karena jauh lebih mudah untuk memahami kapan pertanyaan mulai menjadi lebih kompleks. Kenapa menggunakannya? Apakah ada peningkatan kinerja? The Jawaban singkatnya adalah tidak, tetapi adalah lebih mudah dibaca setelah Anda terbiasa untuk itu. Lebih mudah membaca kueri yang ditulis oleh orang lain menggunakan sintaks ini.
Saya juga akan menggunakan konsep caryard kecil yang memiliki database untuk melacak mobil apa yang telah tersedia. Pemilik telah mempekerjakan Anda sebagai orang IT Computer-nya dan mengharapkan Anda untuk dapat memberikan data yang dia minta pada saat itu.
Saya telah membuat sejumlah tabel pencarian yang akan digunakan oleh tabel final. Ini akan memberi kita model yang masuk akal untuk bekerja. Untuk memulai, saya akan menjalankan kueri terhadap contoh database yang memiliki struktur berikut. Saya akan mencoba memikirkan kesalahan umum yang dibuat ketika memulai dan menjelaskan apa yang salah dengan mereka - dan tentu saja menunjukkan cara memperbaikinya.
Tabel pertama hanyalah daftar warna sehingga kita tahu warna apa yang kita miliki di halaman mobil.
mysql> create table colors(id int(3) not null auto_increment primary key,
-> color varchar(15), paint varchar(10));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from colors;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| color | varchar(15) | YES | | NULL | |
| paint | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> insert into colors (color, paint) values ('Red', 'Metallic'),
-> ('Green', 'Gloss'), ('Blue', 'Metallic'),
-> ('White' 'Gloss'), ('Black' 'Gloss');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from colors;
+----+-------+----------+
| id | color | paint |
+----+-------+----------+
| 1 | Red | Metallic |
| 2 | Green | Gloss |
| 3 | Blue | Metallic |
| 4 | White | Gloss |
| 5 | Black | Gloss |
+----+-------+----------+
5 rows in set (0.00 sec)
Tabel merek mengidentifikasi berbagai merek mobil yang bisa dijual caryard.
mysql> create table brands (id int(3) not null auto_increment primary key,
-> brand varchar(15));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from brands;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| brand | varchar(15) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
mysql> insert into brands (brand) values ('Ford'), ('Toyota'),
-> ('Nissan'), ('Smart'), ('BMW');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from brands;
+----+--------+
| id | brand |
+----+--------+
| 1 | Ford |
| 2 | Toyota |
| 3 | Nissan |
| 4 | Smart |
| 5 | BMW |
+----+--------+
5 rows in set (0.00 sec)
Tabel model akan mencakup berbagai jenis mobil, akan lebih mudah untuk menggunakan jenis mobil yang berbeda daripada model mobil yang sebenarnya.
mysql> create table models (id int(3) not null auto_increment primary key,
-> model varchar(15));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from models;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| model | varchar(15) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> insert into models (model) values ('Sports'), ('Sedan'), ('4WD'), ('Luxury');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from models;
+----+--------+
| id | model |
+----+--------+
| 1 | Sports |
| 2 | Sedan |
| 3 | 4WD |
| 4 | Luxury |
+----+--------+
4 rows in set (0.00 sec)
Dan akhirnya, untuk mengikat semua tabel lainnya, tabel yang mengikat semuanya. Bidang ID sebenarnya nomor lot unik yang digunakan untuk mengidentifikasi mobil.
mysql> create table cars (id int(3) not null auto_increment primary key,
-> color int(3), brand int(3), model int(3));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from cars;
+-------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| color | int(3) | YES | | NULL | |
| brand | int(3) | YES | | NULL | |
| model | int(3) | YES | | NULL | |
+-------+--------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> insert into cars (color, brand, model) values (1,2,1), (3,1,2), (5,3,1),
-> (4,4,2), (2,2,3), (3,5,4), (4,1,3), (2,2,1), (5,2,3), (4,5,1);
Query OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql> select * from cars;
+----+-------+-------+-------+
| id | color | brand | model |
+----+-------+-------+-------+
| 1 | 1 | 2 | 1 |
| 2 | 3 | 1 | 2 |
| 3 | 5 | 3 | 1 |
| 4 | 4 | 4 | 2 |
| 5 | 2 | 2 | 3 |
| 6 | 3 | 5 | 4 |
| 7 | 4 | 1 | 3 |
| 8 | 2 | 2 | 1 |
| 9 | 5 | 2 | 3 |
| 10 | 4 | 5 | 1 |
+----+-------+-------+-------+
10 rows in set (0.00 sec)
Ini akan memberi kita cukup data (saya harap) untuk menutupi contoh-contoh di bawah ini dari berbagai jenis sambungan dan juga memberikan data yang cukup untuk menjadikannya berharga.
Jadi masuk ke grit itu, bos ingin tahu ID semua mobil sport yang dimilikinya .
Ini adalah gabungan dua tabel sederhana. Kami memiliki tabel yang mengidentifikasi model dan tabel dengan stok yang tersedia di dalamnya. Seperti yang Anda lihat, data di model
kolom cars
tabel terkait dengan models
kolom cars
tabel yang kita miliki. Sekarang, kita tahu bahwa tabel model memiliki ID 1
untuk Sports
jadi mari kita menulis join.
select
ID,
model
from
cars
join models
on model=ID
Jadi pertanyaan ini terlihat bagus bukan? Kami telah mengidentifikasi dua tabel dan berisi informasi yang kami butuhkan dan menggunakan gabungan yang mengidentifikasi kolom mana yang akan bergabung.
ERROR 1052 (23000): Column 'ID' in field list is ambiguous
Oh tidak! Kesalahan dalam kueri pertama kami! Ya, dan itu adalah buah prem. Soalnya, kueri memang punya kolom yang tepat, tetapi beberapa di antaranya ada di kedua tabel, sehingga database menjadi bingung tentang apa sebenarnya kolom yang kami maksud dan di mana. Ada dua solusi untuk mengatasi ini. Yang pertama bagus dan sederhana, bisa kita gunakan tableName.columnName
untuk memberi tahu database apa yang kita maksud, seperti ini:
select
cars.ID,
models.model
from
cars
join models
on cars.model=models.ID
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
| 2 | Sedan |
| 4 | Sedan |
| 5 | 4WD |
| 7 | 4WD |
| 9 | 4WD |
| 6 | Luxury |
+----+--------+
10 rows in set (0.00 sec)
Yang lain mungkin lebih sering digunakan dan disebut table aliasing. Tabel dalam contoh ini memiliki nama sederhana yang bagus dan pendek, tetapi mengetikkan sesuatu seperti KPI_DAILY_SALES_BY_DEPARTMENT
mungkin akan menjadi cepat, jadi cara sederhana adalah dengan memberi nama tabel pada tabel seperti ini:
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
Sekarang, kembali ke permintaan. Seperti yang Anda lihat, kami memiliki informasi yang kami butuhkan, tetapi kami juga memiliki informasi yang tidak diminta, jadi kami harus menyertakan klausa di mana dalam pernyataan untuk hanya mendapatkan mobil Sport seperti yang diminta. Karena saya lebih suka metode tabel alias daripada menggunakan nama tabel berulang kali, saya akan tetap menggunakannya sejak saat ini dan seterusnya.
Jelas, kita perlu menambahkan klausa tempat ke kueri kami. Kami dapat mengidentifikasi mobil Sport baik dengan ID=1
atau model='Sports'
. Karena ID diindeks dan kunci utama (dan itu terjadi kurang mengetik), mari kita gunakan dalam kueri kami.
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
where
b.ID=1
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)
Bingo! Bos senang. Tentu saja, sebagai bos dan tidak pernah senang dengan apa yang dia minta, dia melihat informasinya, lalu berkata aku ingin warnanya juga .
Oke, jadi kita sudah memiliki bagian yang baik dari permintaan kita yang sudah ditulis, tetapi kita perlu menggunakan tabel ketiga yang berwarna. Sekarang, tabel informasi utama kami cars
menyimpan ID warna mobil dan tautan ini kembali ke kolom ID warna. Jadi, dengan cara yang mirip dengan aslinya, kita bisa bergabung dengan tabel ketiga:
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
where
b.ID=1
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)
Sial, meskipun tabel bergabung dengan benar dan kolom terkait telah ditautkan, kami lupa untuk menarik informasi aktual dari tabel baru yang baru saja kami tautkan.
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
where
b.ID=1
+----+--------+-------+
| ID | model | color |
+----+--------+-------+
| 1 | Sports | Red |
| 8 | Sports | Green |
| 10 | Sports | White |
| 3 | Sports | Black |
+----+--------+-------+
4 rows in set (0.00 sec)
Benar, itu bos di belakang kita sejenak. Sekarang, untuk menjelaskan beberapa hal ini dengan sedikit lebih detail. Seperti yang Anda lihat, from
klausa dalam pernyataan kami menautkan tabel utama kami (saya sering menggunakan tabel yang berisi informasi daripada tabel pencarian atau dimensi. Kueri akan bekerja sama baiknya dengan semua tabel yang diputar, tetapi kurang masuk akal saat kami kembali ke kueri ini untuk membacanya dalam waktu beberapa bulan, jadi sering kali paling baik untuk mencoba menulis kueri yang bagus dan mudah dipahami - lay out secara intuitif, gunakan indentasi yang bagus sehingga semuanya sejelas seperti Jika Anda terus mengajar orang lain, cobalah untuk menanamkan karakteristik ini dalam permintaan mereka - terutama jika Anda akan memecahkan masalah mereka.
Sangat mungkin untuk terus menautkan semakin banyak tabel dengan cara ini.
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
Meskipun saya lupa menyertakan tabel di mana kami mungkin ingin bergabung lebih dari satu kolom dalam join
pernyataan, berikut adalah contohnya. Jika models
tabel memiliki model khusus merek dan oleh karena itu juga memiliki kolom yang disebut brand
yang terhubung kembali ke brands
tabel di ID
lapangan, bisa dilakukan sebagai berikut:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
and b.brand=d.ID
where
b.ID=1
Anda dapat melihat, kueri di atas tidak hanya menautkan tabel yang bergabung ke tabel utama cars
, tetapi juga menentukan gabungan antara tabel yang sudah bergabung. Jika ini tidak dilakukan, hasilnya disebut bergabung kartesian - yang dba berbicara buruk. Penggabungan kartesian adalah tempat baris dikembalikan karena informasi tidak memberi tahu database cara membatasi hasil, sehingga kueri mengembalikan semua baris yang sesuai dengan kriteria.
Jadi, untuk memberikan contoh gabungan kartesian, mari jalankan query berikut:
select
a.ID,
b.model
from
cars a
join models b
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 1 | Sedan |
| 1 | 4WD |
| 1 | Luxury |
| 2 | Sports |
| 2 | Sedan |
| 2 | 4WD |
| 2 | Luxury |
| 3 | Sports |
| 3 | Sedan |
| 3 | 4WD |
| 3 | Luxury |
| 4 | Sports |
| 4 | Sedan |
| 4 | 4WD |
| 4 | Luxury |
| 5 | Sports |
| 5 | Sedan |
| 5 | 4WD |
| 5 | Luxury |
| 6 | Sports |
| 6 | Sedan |
| 6 | 4WD |
| 6 | Luxury |
| 7 | Sports |
| 7 | Sedan |
| 7 | 4WD |
| 7 | Luxury |
| 8 | Sports |
| 8 | Sedan |
| 8 | 4WD |
| 8 | Luxury |
| 9 | Sports |
| 9 | Sedan |
| 9 | 4WD |
| 9 | Luxury |
| 10 | Sports |
| 10 | Sedan |
| 10 | 4WD |
| 10 | Luxury |
+----+--------+
40 rows in set (0.00 sec)
Ya Tuhan, itu jelek. Namun, sejauh menyangkut database, itu persis apa yang diminta. Dalam kueri, kami meminta ID
dari cars
dan model
dari models
. Namun, karena kami tidak menentukan cara bergabung dengan tabel, database telah mencocokkan setiap baris dari tabel pertama dengan setiap baris dari tabel kedua.
Oke, jadi bos sudah kembali, dan dia ingin lebih banyak informasi lagi. Saya ingin daftar yang sama, tetapi juga menyertakan 4WD di dalamnya .
Namun ini, memberi kita alasan besar untuk melihat dua cara berbeda untuk mencapai ini. Kita dapat menambahkan kondisi lain ke klausa di mana seperti ini:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
or b.ID=3
Meskipun hal di atas akan bekerja dengan baik, mari kita lihat secara berbeda, ini adalah alasan yang bagus untuk menunjukkan bagaimana sebuah union
kueri akan bekerja.
Kita tahu bahwa yang berikut akan mengembalikan semua mobil Sport:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
Dan yang berikut ini akan mengembalikan semua 4WD:
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=3
Jadi dengan menambahkan union all
klausa di antara mereka, hasil permintaan kedua akan ditambahkan ke hasil permintaan pertama.
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
union all
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=3
+----+--------+-------+
| ID | model | color |
+----+--------+-------+
| 1 | Sports | Red |
| 8 | Sports | Green |
| 10 | Sports | White |
| 3 | Sports | Black |
| 5 | 4WD | Green |
| 7 | 4WD | White |
| 9 | 4WD | Black |
+----+--------+-------+
7 rows in set (0.00 sec)
Seperti yang Anda lihat, hasil dari query pertama dikembalikan terlebih dahulu, diikuti oleh hasil dari query kedua.
Dalam contoh ini, tentu saja akan jauh lebih mudah untuk hanya menggunakan kueri pertama, tetapi union
kueri bisa bagus untuk kasus-kasus tertentu. Mereka adalah cara yang bagus untuk mengembalikan hasil spesifik dari tabel dari tabel yang tidak mudah bergabung bersama - atau dalam hal ini tabel yang sama sekali tidak terkait. Namun ada beberapa aturan yang harus diikuti.
- Jenis kolom dari kueri pertama harus cocok dengan jenis kolom dari setiap kueri lainnya di bawah ini.
- Nama-nama kolom dari kueri pertama akan digunakan untuk mengidentifikasi seluruh rangkaian hasil.
- Jumlah kolom di setiap kueri harus sama.
Sekarang, Anda mungkin bertanya-tanya apa perbedaan antara menggunakan union
dan union all
. Sebuah union
permintaan akan menghapus duplikat, sementara union all
tidak akan. Ini berarti bahwa ada hit kinerja kecil ketika menggunakan union
lebih dari union all
tetapi hasilnya mungkin sepadan - saya tidak akan berspekulasi pada hal semacam itu dalam hal ini sekalipun.
Pada catatan ini, mungkin perlu dicatat beberapa catatan tambahan di sini.
- Jika kami ingin memesan hasilnya, kami dapat menggunakan
order by
tetapi Anda tidak dapat menggunakan alias lagi. Dalam kueri di atas, menambahkan suatu order by a.ID
akan menghasilkan kesalahan - sejauh menyangkut hasil, kolom disebut ID
bukan a.ID
- meskipun alias yang sama telah digunakan di kedua kueri.
- Kami hanya dapat memiliki satu
order by
pernyataan, dan itu harus sebagai pernyataan terakhir.
Untuk contoh berikutnya, saya menambahkan beberapa baris tambahan ke tabel kami.
Saya telah menambahkan Holden
ke tabel merek. Saya juga menambahkan baris ke dalam cars
yang memiliki color
nilai 12
- yang tidak memiliki referensi dalam tabel warna.
Oke, bos kembali lagi, menggonggong permintaan - * Saya ingin hitungan masing-masing merek yang kami bawa dan jumlah mobil di dalamnya! .
Rightyo, jadi hal pertama yang perlu kita lakukan adalah mendapatkan daftar lengkap merek yang mungkin.
select
a.brand
from
brands a
+--------+
| brand |
+--------+
| Ford |
| Toyota |
| Nissan |
| Smart |
| BMW |
| Holden |
+--------+
6 rows in set (0.00 sec)
Sekarang, ketika kita bergabung ini ke meja mobil kita, kita mendapatkan hasil berikut:
select
a.brand
from
brands a
join cars b
on a.ID=b.brand
group by
a.brand
+--------+
| brand |
+--------+
| BMW |
| Ford |
| Nissan |
| Smart |
| Toyota |
+--------+
5 rows in set (0.00 sec)
Yang tentu saja merupakan masalah - kami tidak melihat penyebutan Holden
merek indah yang saya tambahkan.
Ini karena gabungan mencari baris yang cocok di kedua tabel. Karena tidak ada data di mobil yang bertipe Holden
tidak dikembalikan. Di sinilah kita bisa menggunakan outer
gabungan. Ini akan mengembalikan semua hasil dari satu tabel apakah mereka cocok di tabel lain atau tidak:
select
a.brand
from
brands a
left outer join cars b
on a.ID=b.brand
group by
a.brand
+--------+
| brand |
+--------+
| BMW |
| Ford |
| Holden |
| Nissan |
| Smart |
| Toyota |
+--------+
6 rows in set (0.00 sec)
Sekarang kita memiliki itu, kita dapat menambahkan fungsi agregat yang indah untuk mendapatkan hitungan dan membuat bos mundur sejenak.
select
a.brand,
count(b.id) as countOfBrand
from
brands a
left outer join cars b
on a.ID=b.brand
group by
a.brand
+--------+--------------+
| brand | countOfBrand |
+--------+--------------+
| BMW | 2 |
| Ford | 2 |
| Holden | 0 |
| Nissan | 1 |
| Smart | 1 |
| Toyota | 5 |
+--------+--------------+
6 rows in set (0.00 sec)
Dan dengan itu, singkirkan bos yang susah.
Sekarang, untuk menjelaskan ini secara lebih rinci, sambungan luar bisa dari tipe left
atau right
. Kiri atau Kanan menentukan tabel mana yang sepenuhnya disertakan. A left outer join
akan memasukkan semua baris dari tabel di sebelah kiri, sementara (Anda dapat menebaknya) a right outer join
membawa semua hasil dari tabel di sebelah kanan ke dalam hasil.
Beberapa database akan memungkinkan full outer join
yang akan mengembalikan hasil (apakah cocok atau tidak) dari kedua tabel, tetapi ini tidak didukung di semua database.
Sekarang, saya mungkin memikirkan saat ini, Anda bertanya-tanya apakah Anda dapat menggabungkan jenis bergabung dalam kueri - dan jawabannya adalah ya, Anda benar-benar bisa.
select
b.brand,
c.color,
count(a.id) as countOfBrand
from
cars a
right outer join brands b
on b.ID=a.brand
join colors c
on a.color=c.ID
group by
a.brand,
c.color
+--------+-------+--------------+
| brand | color | countOfBrand |
+--------+-------+--------------+
| Ford | Blue | 1 |
| Ford | White | 1 |
| Toyota | Black | 1 |
| Toyota | Green | 2 |
| Toyota | Red | 1 |
| Nissan | Black | 1 |
| Smart | White | 1 |
| BMW | Blue | 1 |
| BMW | White | 1 |
+--------+-------+--------------+
9 rows in set (0.00 sec)
Jadi, mengapa itu bukan hasil yang diharapkan? Itu karena meskipun kami telah memilih gabung luar dari mobil ke merek, itu tidak ditentukan dalam gabung ke warna - sehingga gabung tertentu hanya akan membawa kembali hasil yang cocok di kedua tabel.
Berikut adalah kueri yang akan berfungsi untuk mendapatkan hasil yang kami harapkan:
select
a.brand,
c.color,
count(b.id) as countOfBrand
from
brands a
left outer join cars b
on a.ID=b.brand
left outer join colors c
on b.color=c.ID
group by
a.brand,
c.color
+--------+-------+--------------+
| brand | color | countOfBrand |
+--------+-------+--------------+
| BMW | Blue | 1 |
| BMW | White | 1 |
| Ford | Blue | 1 |
| Ford | White | 1 |
| Holden | NULL | 0 |
| Nissan | Black | 1 |
| Smart | White | 1 |
| Toyota | NULL | 1 |
| Toyota | Black | 1 |
| Toyota | Green | 2 |
| Toyota | Red | 1 |
+--------+-------+--------------+
11 rows in set (0.00 sec)
Seperti yang dapat kita lihat, kita memiliki dua gabungan luar dalam kueri dan hasilnya akan seperti yang diharapkan.
Sekarang, bagaimana dengan jenis-jenis sambungan yang Anda tanyakan? Bagaimana dengan titik-temu?
Yah, tidak semua database mendukung, intersection
tetapi hampir semua database akan memungkinkan Anda untuk membuat persimpangan melalui gabungan (atau pernyataan yang terstruktur dengan baik setidaknya).
Persimpangan adalah jenis gabungan yang agak mirip dengan yang union
dijelaskan di atas - tetapi perbedaannya adalah bahwa ia hanya mengembalikan baris data yang identik (dan maksud saya identik) antara berbagai kueri individual yang digabungkan oleh serikat. Hanya baris yang identik dalam setiap hal yang akan dikembalikan.
Contoh sederhana akan seperti itu:
select
*
from
colors
where
ID>2
intersect
select
*
from
colors
where
id<4
Sementara union
kueri normal akan mengembalikan semua baris tabel (kueri pertama mengembalikan apa pun ID>2
dan yang kedua memiliki ID<4
), yang akan menghasilkan set lengkap, kueri intersect hanya akan mengembalikan pencocokan baris id=3
karena memenuhi kedua kriteria.
Sekarang, jika basis data Anda tidak mendukung intersect
kueri, hal di atas dapat dengan mudah dilakukan dengan kueri berikut:
select
a.ID,
a.color,
a.paint
from
colors a
join colors b
on a.ID=b.ID
where
a.ID>2
and b.ID<4
+----+-------+----------+
| ID | color | paint |
+----+-------+----------+
| 3 | Blue | Metallic |
+----+-------+----------+
1 row in set (0.00 sec)
Jika Anda ingin melakukan persimpangan di dua tabel yang berbeda menggunakan database yang secara inheren tidak mendukung kueri persimpangan, Anda perlu membuat gabungan di setiap kolom tabel.
Ok, saya menemukan posting ini sangat menarik dan saya ingin berbagi pengetahuan saya tentang membuat kueri. Terima kasih untuk Fluffeh ini . Orang lain yang mungkin membaca ini dan mungkin merasa bahwa saya salah 101% bebas untuk mengedit dan mengkritik jawaban saya. ( Jujur, saya merasa sangat berterima kasih karena memperbaiki kesalahan saya. )
Saya akan memposting beberapa pertanyaan umum dalam
MySQL
tag.Trik No. 1 ( baris yang cocok dengan berbagai kondisi )
Diberikan skema ini
PERTANYAAN
Temukan semua film yang termasuk setidaknya dalam kategori
Comedy
danRomance
kategori.Larutan
Pertanyaan ini terkadang sangat rumit. Tampaknya pertanyaan seperti ini akan menjadi jawabannya: -
Demo SQLFiddle
yang pasti sangat salah karena menghasilkan hasil . Penjelasan dari ini adalah bahwa hanya ada satu nilai yang valid
CategoryName
pada setiap baris . Misalnya, kondisi pertama mengembalikan true , kondisi kedua selalu salah. Jadi, dengan menggunakanAND
operator, kedua kondisi tersebut harus benar; jika tidak, itu akan salah. Kueri lain seperti ini,Demo SQLFiddle
dan hasilnya masih salah karena cocok dengan catatan yang sudah setidaknya satu kecocokan pada
categoryName
. The solusi nyata akan dengan menghitung jumlah kasus record per film . Jumlah instance harus sesuai dengan jumlah total nilai yang disediakan dalam kondisi.SQLFiddle Demo (jawabannya)
Trick No. 2 ( catatan maksimum untuk setiap entri )
Skema yang diberikan,
PERTANYAAN
Temukan versi terbaru pada setiap perangkat lunak. Menampilkan kolom berikut:
SoftwareName
,Descriptions
,LatestVersion
( dari kolom VersionNo ),DateReleased
Larutan
Beberapa pengembang SQL keliru menggunakan
MAX()
fungsi agregat. Mereka cenderung membuat seperti ini,Demo SQLFiddle
( kebanyakan RDBMS menghasilkan kesalahan sintaksis karena ini tidak menentukan beberapa kolom non-agregat pada
group by
klausa ) hasilnya menghasilkan yang benarLatestVersion
pada setiap perangkat lunak tetapi jelasDateReleased
tidak benar.MySQL
tidak mendukungWindow Functions
danCommon Table Expression
belum sebagaimana beberapa RDBMS sudah lakukan. Solusi untuk masalah ini adalah membuatsubquery
yang mendapat maksimum individuversionNo
pada setiap perangkat lunak dan kemudian bergabung di tabel lainnya.SQLFiddle Demo (jawabannya)
Jadi begitulah. Saya akan posting segera lain seperti yang saya ingat lain FAQ di
MySQL
tag. Terima kasih telah membaca artikel kecil ini. Saya harap Anda setidaknya mendapatkan sedikit pengetahuan dari ini.PEMBARUAN 1
Trik No. 3 ( Menemukan catatan terbaru antara dua ID )
Skema yang diberikan
PERTANYAAN
Temukan percakapan terbaru antara dua pengguna.
Larutan
Demo SQLFiddle
sumber
comedy
danromance
.Having
tidak sesuai dengan itu ..distinct
pada klausa yang ada Demo SQLFiddle : DBagian 2 - Subqueries
Oke, sekarang bos sudah masuk lagi - saya ingin daftar semua mobil kami dengan merek dan total berapa banyak merek yang kita miliki!
Ini adalah kesempatan bagus untuk menggunakan trik berikutnya dalam tas kita tentang barang-barang SQL - subquery. Jika Anda tidak terbiasa dengan istilah tersebut, subquery adalah kueri yang berjalan di dalam kueri lain. Ada banyak cara untuk menggunakannya.
Untuk permintaan kami, pertama-tama mari kita satukan pertanyaan sederhana yang akan mencantumkan setiap mobil dan merek:
Sekarang, jika kami hanya ingin menghitung jumlah mobil yang disortir berdasarkan merek, tentu saja kami dapat menulis ini:
Jadi, kita harus bisa dengan mudah menambahkan fungsi hitungan ke permintaan asli kita, kan?
Sayangnya, tidak, kita tidak bisa melakukan itu. Alasannya adalah bahwa ketika kita menambahkan ID mobil (kolom a.ID) kita harus menambahkannya ke dalam grup - jadi sekarang, ketika fungsi penghitungan bekerja, hanya ada satu ID yang cocok dengan setiap ID.
Di sinilah kita bisa menggunakan subquery - sebenarnya kita bisa melakukan dua tipe subquery yang sama sekali berbeda yang akan mengembalikan hasil yang sama yang kita butuhkan untuk ini. Yang pertama adalah cukup menempatkan subquery dalam
select
klausa. Ini berarti setiap kali kita mendapatkan satu baris data, subquery akan lari, mendapatkan kolom data dan kemudian memasukkannya ke dalam baris data kita.Dan Bam !, ini akan membantu kita. Jika Anda perhatikan, sub kueri ini harus dijalankan untuk setiap baris data yang kami kembalikan. Bahkan dalam contoh kecil ini, kami hanya memiliki lima Merek mobil yang berbeda, tetapi subquery tersebut berjalan sebelas kali karena kami memiliki sebelas baris data yang akan kami kembalikan. Jadi, dalam hal ini, sepertinya bukan cara paling efisien untuk menulis kode.
Untuk pendekatan yang berbeda, mari jalankan subquery dan anggap itu adalah tabel:
Oke, jadi kami memiliki hasil yang sama (dipesan sedikit berbeda - sepertinya database ingin mengembalikan hasil yang dipesan oleh kolom pertama yang kami pilih kali ini) - tetapi angka yang tepat sama.
Jadi, apa perbedaan antara keduanya - dan kapan kita harus menggunakan masing-masing jenis subquery? Pertama, mari pastikan kita memahami cara kerja kueri kedua itu. Kami memilih dua tabel dalam
from
klausa kueri kami, dan kemudian menulis kueri dan memberi tahu database bahwa itu sebenarnya sebuah tabel - yang mana database tersebut sangat cocok digunakan. Ada bisa ada beberapa manfaat untuk menggunakan metode ini (serta beberapa keterbatasan). Yang terpenting adalah bahwa subquery ini berjalan sekali . Jika basis data kami berisi sejumlah besar data, mungkin ada peningkatan besar-besaran atas metode pertama. Namun, karena kami menggunakan ini sebagai tabel, kami harus membawa baris data tambahan - sehingga mereka dapat benar-benar digabungkan kembali ke baris data kami. Kami juga harus memastikan bahwa ada cukupbaris data jika kita akan menggunakan gabungan sederhana seperti pada kueri di atas. Jika Anda ingat, gabungan hanya akan menarik kembali baris yang memiliki data yang cocok di kedua sisi gabungan. Jika kami tidak berhati-hati, ini dapat mengakibatkan data yang valid tidak dikembalikan dari tabel mobil kami jika tidak ada baris yang cocok dalam subquery ini.Sekarang, melihat kembali pada subquery pertama, ada beberapa batasan juga. karena kita menarik data kembali ke satu baris, kita HANYA dapat menarik kembali satu baris data. Subqueries yang digunakan dalam
select
klausa query sangat sering hanya menggunakan fungsi agregat sepertisum
,count
,max
atau fungsi lain agregat serupa. Mereka tidak harus melakukannya, tetapi sering kali itulah cara mereka ditulis.Jadi, sebelum kita melanjutkan, mari kita lihat di mana lagi kita bisa menggunakan subquery. Kita dapat menggunakannya dalam
where
klausa - sekarang, contoh ini sedikit dibuat-buat seperti dalam database kami, ada cara yang lebih baik untuk mendapatkan data berikut, tetapi melihat hanya sebagai contoh, mari kita lihat:Ini mengembalikan daftar ID merek dan nama Merek (kolom kedua hanya ditambahkan untuk menunjukkan kepada kami merek) yang berisi huruf
o
dalam nama tersebut.Sekarang, kita bisa menggunakan hasil dari kueri ini di mana klausa ini:
Seperti yang Anda lihat, meskipun subquery mengembalikan tiga ID merek, meja mobil kami hanya memiliki entri untuk dua dari mereka.
Dalam hal ini, untuk perincian lebih lanjut, subquery berfungsi seolah-olah kita menulis kode berikut:
Sekali lagi, Anda dapat melihat bagaimana input subquery vs manual telah mengubah urutan baris ketika kembali dari database.
Sementara kita membahas subquery, mari kita lihat apa lagi yang bisa kita lakukan dengan subquery:
select
klausa, beberapa di dalamfrom
klausa dan beberapa lagi di dalamwhere
klausa - ingatlah bahwa masing-masing yang Anda masukkan membuat kueri Anda lebih kompleks dan cenderung membutuhkan waktu lebih lama untuk menjalankan.Jika Anda perlu menulis beberapa kode yang efisien, akan bermanfaat untuk menulis kueri beberapa cara dan melihat (baik dengan menentukan waktu atau dengan menggunakan menjelaskan rencana) yang merupakan kueri optimal untuk mendapatkan hasil Anda. Cara pertama yang berhasil mungkin tidak selalu menjadi cara terbaik untuk melakukannya.
sumber
Bagian 3 - Trik dan Kode Efisien
MySQL dalam () efisiensi
Saya pikir saya akan menambahkan beberapa bit tambahan, untuk tips dan trik yang telah muncul.
Satu pertanyaan yang saya lihat muncul sedikit adil, adalah Bagaimana cara mendapatkan baris yang tidak cocok dari dua tabel dan saya melihat jawaban yang paling umum diterima sebagai sesuatu seperti berikut (berdasarkan tabel mobil dan merek kami - yang Holden terdaftar sebagai merek, tetapi tidak muncul di tabel mobil):
Dan ya itu akan berhasil.
Namun itu tidak efisien dalam beberapa database. Berikut ini tautan ke pertanyaan Stack Overflow yang menanyakannya, dan di sini ada artikel mendalam yang sangat bagus jika Anda ingin masuk ke seluk-beluk seluk beluk.
Jawaban singkatnya adalah, jika optimizer tidak menanganinya secara efisien, mungkin lebih baik menggunakan kueri seperti berikut untuk mendapatkan baris yang tidak cocok:
Perbarui Tabel dengan tabel yang sama di subquery
Ahhh, oldie lain tapi goodie - yang lama Anda tidak dapat menentukan 'target' tabel target untuk pembaruan dalam klausa FROM .
MySQL tidak akan mengizinkan Anda untuk menjalankan
update...
kueri dengan sub-pilihan pada tabel yang sama. Sekarang, Anda mungkin berpikir, mengapa tidak menampar klausa itu? Tetapi bagaimana jika Anda ingin memperbarui hanya baris denganmax()
tanggal di antara sekelompok baris lainnya? Anda tidak bisa melakukan itu di klausa mana.Jadi, kita tidak bisa melakukan itu, eh? Ya tidak. Ada solusi tersembunyi yang tidak diketahui oleh sejumlah besar pengguna - meskipun ini termasuk beberapa peretasan yang perlu Anda perhatikan.
Anda bisa menempelkan subquery di dalam subquery lain, yang menempatkan cukup banyak celah di antara dua kueri sehingga akan berfungsi. Namun, perhatikan bahwa mungkin paling aman untuk tetap menggunakan kueri dalam transaksi - ini akan mencegah perubahan lain yang dibuat ke tabel saat kueri berjalan.
sumber
Anda dapat menggunakan konsep beberapa kueri dalam kata kunci FROM. Mari saya tunjukkan satu contoh:
Anda bisa menggunakan tabel sebanyak yang Anda mau. Gunakan gabungan luar dan penyatuan di mana pun itu diperlukan, bahkan di dalam subqueries tabel.
Itu metode yang sangat mudah untuk melibatkan sebanyak tabel dan bidang.
sumber
Berharap ini membuatnya menemukan tabel saat Anda membaca hal:
jsfiddle
sumber