HA

outer apply 和 left join 再辨析

outer apply 和 left join 再辨析

  1. 過濾條件位置不同(看下面例子可以看出來)
  2. outer apply可以較方便地實現控制參照表參照記錄的個數,left join稍微麻煩一些

下面要實現一個需求,現在有兩個表,一個作者表(裡面主要有作者名稱字段、作者id字段)、還有一個書籍表(主要有書籍名稱、作者id、價格)。現在我們需要找出查出作者信息,同時要參照出該作者所寫書籍中價格最高的一本書的名字、價格。

mssql

--加查詢條件是為了顯示效果,去掉沒用的記錄
--兩個表的信息 圖一
select * from author where author_id in (1, 2, 3);
select * from book where author_id in (1, 2, 3) 
order by author_id,price desc;
--outer apply實現 圖二 上
select main.*, isnull(sub.book_name, '') as book_name, isnull(sub.price, 0) as price
from author main
outer apply (select top 1 book_name, price 
           from book s 
		   where s.author_id = main.author_id
		   order by price
) sub
where isnull(sub.price, 0) > 0;
--left join實現 圖二下
select main.*, isnull(sub.book_name, '') as book_name, isnull(sub.price, 0) as price
from author main
left join book sub on sub.author_id = main.author_id
                      and sub.id = (select top 1 s.id 
					                from book s
									where s.author_id = main.author_id)
where isnull(sub.price, 0) > 0;
--錯誤語句 
select main.*,sub.book_name
from author main
left join (select top 1 book_name 
           from book s 
		   where s.author_id = main.author_id --无法绑定由多个部分组成的标识符 "main.author_id"。可看出在這個位置獲取不到主表的數據
) sub on (1=1);
--在outer apply的別名後也不能再進行過濾了
select main.*, isnull(sub.book_name, '') as book_name, isnull(sub.price, 0) as price
from author main
outer apply (select top 1 book_name, price 
           from book s 
		   where s.author_id = main.author_id
		   order by price
) sub on (1=1)--該處有語法錯誤
where isnull(sub.price, 0) > 0;

--參照表更新表數據的方式 雖然下面語句參照完全沒有必要
update main
set main.age = main.age + 1
from author main
inner join book sub on sub.author_id in (1, 2, 3) 
           and main.author_id = sub.author_id;

圖一 圖二

mysql

create table fruit(
fruit_name char(40) not null,
fruit_id int(5) not null,
id int not null auto_increment,
primary key(id)
)
/*關閉安全更新模式,同時參照子表更新主表*/
set sql_safe_updates = 0;
update fruit_month_price main
inner join fruit sub on sub.fruit_name = main.name
set main.fruit_id = sub.fruit_id;
/*查詢水果表,並參照出價格價格最高所在記錄的數量和價格*/
select main.*, ifnull(sub.num, 0) as num, ifnull(sub.price, 0) as price
from fruit main
left join fruit_month_price sub on main.fruit_id = sub.fruit_id
								   and sub.id = (select id from fruit_month_price s
                                                  where s.fruit_id = main.fruit_id
                                                  order by price desc
                                                  limit 1)

reference

  1. How to limit results of a LEFT JOIN
  2. LEFT JOIN only first row
  3. SQL Server - inner join when updating [duplicate]
  4. MYSQL Update Statement Inner Join Tables
  5. MySQL error code: 1175 during UPDATE in MySQL Workbench
  6. MySql 里的IFNULL、NULLIF和ISNULL用法