SQL Join の使用方法の詳細な説明 (添付: 各グループの最初の N レコードのグループ クエリ)

1. 基本的な考え方

SQL文のjoinキーワードについて、よく使われるキーワードですがわかりにくいので、テーブルuser1、user2の作成例で簡単に説明します。

table1 : create table user2(id int, user_name varchar(10), over varchar(10));
insert into user1 values(1, ‘tangseng', ‘dtgdf');
insert into user1 values(2, ‘sunwukong', ‘dzsf');
insert into user1 values(1, ‘zhubajie', ‘jtsz');
insert into user1 values(1, ‘shaseng', ‘jslh');
table2 : create table user2(id int, user_name varchar(10), over varchar(10));
insert into user2 values(1, ‘sunwukong', ‘chengfo');
insert into user2 values(2, ‘niumowang', ‘chengyao');
insert into user2 values(3, ‘jiaomowang', ‘chengyao');
insert into user2 values(4, ‘pengmowang', ‘chengyao');

SQL 標準における結合の種類
ここに画像の説明を挿入します

  1. 内部結合 (内部結合または結合)

(1). 概念: 内部結合は、結合述語に基づいて 2 つのテーブルの列を結合し、新しい結果テーブルを生成します。

(2).内部接続ベン図:
ここに画像の説明を挿入します

(3).sql文

select a.id, a.user_name, b.over 
from user1 a 
inner join user2 b 
on a.user_name=b.user_name;

結果:
ここに画像の説明を挿入します

  1. 外部結合

外部結合には、左外部結合、右外部結合、または完全外部結合が含まれます。

a. 左外部結合: 左結合または左外部結合
(1) 概念: 左外部結合の結果セットには、結合列と一致する行だけでなく、LEFT OUTER 句で指定された左表のすべての行が含まれます。左側のテーブルの行に右側のテーブルに一致する行がない場合、右側のテーブルのすべての選択リスト列は、関連する結果セット行で null になります。

(2) 左外部結合ベン図:
ここに画像の説明を挿入します

(3)SQL文:

select a.id, a.user_name, b.over 
from user1 a 
left join user2 b 
on a.user_name=b.user_name;

結果:
ここに画像の説明を挿入します

b. 右外部結合:右外部結合または右外部結合
(1) 右外部結合は、左外部結合の逆結合です。右側のテーブルのすべての行が返されます。右側のテーブルの行に左側のテーブルに一致する行がない場合、左側のテーブルに対して null が返されます。
(2) 右外部結合ベン図:
ここに画像の説明を挿入します

(3)SQL文

select b.user_name, b.over, a.over 
from user1 a 
right join user2 b 
on a.user_name=b.user_name;

結果:
ここに画像の説明を挿入します

c. 完全外部結合: 完全外部結合または完全外部結合

(1) 完全な外部結合は、左右のテーブルのすべての行を返します。行に別のテーブルに一致する行がない場合、他のテーブルの選択リスト列には NULL 値が含まれます。テーブル間に一致する行がある場合、結果セットの行全体にベース テーブルのデータ値が含まれます。
(2) 右外部結合ベン図:
ここに画像の説明を挿入します

(3)SQL文

select a.id, a.user_name, b.over 
from user1 a 
full join user2 b 
on a.user_name=b.user_name

mysql で完全な接続をクエリすると、エラー 1064 が報告されます。Mysql は完全な接続クエリをサポートしていません。ステートメントの代わりに、次のようにします。

select a.user_name,a.over,b.over 
from user1 a left join user2 b 
on a.user_name = b.user_name 
union all select b.user_name,b.over ,a.over 
from user1 a 
right join user2 b 
on a.user_name = b.user_name;

結果:
ここに画像の説明を挿入します

  1. デカルト結合 (クロス結合)

1. 概念: WHERE 句を使用しないクロス結合では、結合に含まれるテーブルのデカルト積が生成されます。最初のテーブルの行数と 2 番目のテーブルの行数を乗算すると、デカルト積の結果セットのサイズに等しくなります。(user1 と user2 の相互接続により、4*4=16 レコードが生成されます)
2. クロス結合: クロス結合 (条件なし)
3. SQL ステートメント:

select a.user_name,b.user_name, a.over, b.over 
from user1 a cross join user2 b;

2. 使用スキル

  1. join を使用したテーブルの更新
    次のステートメントを使用して、user1 テーブルと user2 テーブルの両方のレコードを含む user1 テーブルの over フィールドを「qtda」に更新します。
update user1 set over='qtds'
where user1.user_name in (
	select b.user_name 
	from user1 a 
	inner join user2 b 
	on a.user_name = b.user_name);

このステートメントは SQL Server と Oracle では正しく実行できますが、mysql ではエラーが報告されます。Mysql はサブクエリ テーブルの更新をサポートしていないため、次のステートメントを使用して実行できます。

update user1 a 
join (
	select b.user_name 
	from user1 a 
	join user2 b 
	on a.user_name = b.user_name) b 
on a.user_name = b.user_name 
set a.over = ‘qtds'
  1. 結合を使用してサブクエリを最適化する

サブクエリの効率が比較的低いため、次のステートメントを使用してクエリを実行します。

select a.user_name, a.over,(
	select over 
	from user2 b 
	where a.user_name=b.user_name) 
as over2 from user1 a;

結合を使用してサブクエリを最適化すると、同じ効果が得られます

select a.user_name, a.over, b.over as over2 
from user1 a 
left join user2 b 
on a.user_name = b.user_name;
  1. 結合を使用して集計サブクエリを最適化する

新しいテーブルを導入します。

user_kills
create table user_kills(user_id int, timestr varchar(20), kills int(10));
insert into user_kills values(2,2015-5-12', 20);
insert into user_kills values(2, ‘2015-5-15', 18);
insert into user_kills values(3,2015-5-11', 16);
insert into user_kills values(3, ‘2015-5-14', 13);
insert into user_kills values(3,2015-5-16', 17);
insert into user_kills values(4, ‘2015-5-12', 16);
insert into user_kills values(4,2015-5-10', 13);

user1 の各人物に対応する user_kills テーブル内の最大キル数の日付をクエリするには、集約サブクエリ ステートメントを使用します。

select a.user_name,b.timestr, b.kills 
from user1 a 
join user_kills b 
on a.id = b.user_id 
where b.kills = (
	select MAX(c.kills) 
	from user_kills c 
	where c.user_id = b.user_id);

結合を使用して集計サブクエリを最適化する (サブクエリを避ける)

select a.user_name, b.timestr, b.kills 
from user1 a 
join user_kills b 
on a.id = b.user_id 
join user_kills c 
on c.user_id = b.user_id 
group by a.user_name, b.timestr, b.kills 
having b.kills = max(c.kills);

結果:
ここに画像の説明を挿入します

  1. グループ選択データの実装

(この要件は、当時の職場では非常に苦痛でした。状況は変わりつつあります。複数の状況のバージョンについては後で整理します。)
user1 の各人物の最多キルの 2 日前をクエリする必要があります。
まず、次のステートメントを使用して、人が最も多く殺害された 2 日をクエリします。

select a.user_name, b.timestr, b.kills 
from user1 a 
join user_kills b 
on a.id = b.user_id 
where a.user_name ='sunwukong' 
order by b.kills desc limit 2;

では、1 つのステートメントを使用して、すべての人の中で最も多くのキルがあった 2 日間をクエリするにはどうすればよいでしょうか? 次のステートメントを見てください。

WITH tmp AS (
select a.user_name, b.timestr, b.kills, ROW_NUMBER() over(
partition by a.user_name order by b.kills) cnt 
from user1 a join user_kills b on a.id = b.user_id) 
select * from tmp where cnt <= 2;

上記のステートメントは、SQL Server と Oracle の両方でサポートされていますが、mysql バージョン 5.7 以下では、グループ化ソート関数 ROW_NUMBER() と一時テーブルの作成をサポートしていません。代替方法を以下に示します。

select d.user_name,c.timestr, kills 
from (select user_id, timestr, kills, (
				select count(*) 
				from user_kills b 
				where b.user_id = a.user_id and a.kills <= b.kills) as cnt 			from user_kills a 
				group by user_id, timestr, kills) c 
join user1 d 
on c.user_id = d.id 
where cnt <= 2;

結果:
ここに画像の説明を挿入します
スクリプトハウスより転載

おすすめ

転載: blog.csdn.net/m0_46364149/article/details/123046979