1. 程式人生 > >查詢在一張表不在另外一張表的記錄

查詢在一張表不在另外一張表的記錄

參考文獻

http://www.cnblogs.com/xwdreamer/archive/2012/06/01/2530597.html

題目

假如要查詢在a表中存在,但是在b表中不存在的記錄,應該如何查詢。為了便於說明,我們假設a表和b表都只有一個欄位id,a表中的記錄為{1,2,3,4,5},b表中的記錄為{2,4},那麼我們需要通過一個sql查詢得到{1,3,5}這樣的結果集。

一般解法(效率低)

看到這個題目,我們首先想到的可能就是not in這樣的關鍵字,具體的查詢語句如下:


select ta.* from ta where ta.id not in(select tb.id from tb)
上述查詢語句的查詢結果集確實是{1,3,5},用navicat執行上述語句,得到如下圖所示結果:

效率分析

但是仔細分析我們可以發現,如果b表很長,那麼執行上述的查詢語句,需要用a表中的欄位去匹配b表中的每一個欄位,相當於是a表的每一個欄位都要遍歷一次b表,效率非常低下。(只要a中的欄位不在b表中那麼肯定要遍歷完b表,如果a表中的欄位在b表中,那麼只要遍歷到就退出,進行a表中下一個欄位的匹配)

使用連線解決

連線查詢使我們平時進行sql查詢用到最多的操作之一了,相對於上述not in關鍵字,我們使用連線查詢的效率更高。因為我們需要搜尋的是a表中的內容,所以使用a表左連線b表,這樣b表中會補null,查詢語句如下:

select * from ta left join tb on ta.id=
tb.id

上述查詢語句的查詢結果如下:

因為a、b兩表中欄位id相同,所以上述b表中的id欄位變成了id1。仔細觀察由可以發現,我們需要的結果集{1,3,5}所對應的id1欄位都是null。這樣我們在上述的查詢語句中加入條件即可完成對只在a表中,但不在b表中的結果集的插敘,查詢語句如下:

select * from ta left join tb on ta.id=tb.id where tb.id is null

查詢結果如下圖所示:

但是我們又發現上述查詢結果有2列,也就是a表和b表的連線查詢結果,但是我們只需要a表中的內容,所以對上述查詢稍作修改:

select ta.* from
ta left join tb on ta.id=tb.id where tb.id is null

查詢結果如下圖所示:

以上就是我們所要求的查詢結果。

詳解(PS:2012-9-7)

時隔三個月再來看這道題目,又有新的發現,之前還是隻是半知半解,在寫完SQL Server Join方式這篇部落格以後基本就明白這道題目的核心了,核心是:我應該使用何種聯接方式來查詢結果。

我們能夠寫出來的最直觀的TSQL語句應該是:

select ta.* from ta where ta.id not in(select tb.id from tb)

然後我們看看這個語句的查詢計劃:

從上圖我們可以發現使用了Nested Loops的聯接方式,但是我們知道nested loop聯接方式的使用場景是:比較適合於兩個比較小的結果集做聯接,或者至少是Outer table的結果集比較小而上面的outer table是ta,它是大表,所以可以發現nested loop不適合。注意:雖然上面的查詢語句中沒有join欄位,但是還是使用了join。

假如我們使用left join 來寫查詢語句的話,sql server會幫我們選擇何種聯接方式呢?測試如下:

select ta.id from ta left join tb on ta.id=tb.id where tb.id is NULL--Hash Match

上述查詢的執行執行計劃如下圖所示:

從上圖我們可以發現sql server幫我們選擇了使用Hash Match。這是因為在上述聯接中,ta是大表,ta和tb兩表之間資料量差距很大,還有ta和tb都沒有索引。從執行計劃的TotalSubtreeCost中也可以看出來,使用Hash Match的TotalSubtreeCost=0.12,而是用Nested Loop的TotalSubtreeCost=1.03。可以發現Hash Match效能比Nest Loop好很多。

那麼使用Merge Join能,起效能如何?我們可以通過使用sql hint來建議sql server使用特定的聯接方式,執行如下TSQL語句:

select ta.id from ta left merge join tb on ta.id=tb.id where tb.id is NULL--Merge Join

其執行計劃如下圖所示:

從上圖可以看出:

  1. 因為查詢列上都沒有索引,所以查詢出來的結果不一定是排序的,這樣sql server幫我們做了排序操作。
  2. 在做完排序操作以後進行的是Merge Join操作,整個查詢所使用的TotalSubtreeCost=0.69,好於Nested Loop,比Hash Match效能差。

所以我們在回答上面題目的時候,必須說明使用Hash Match,而不只是給出left join的答案,之所以查詢結果最有是因為sql server幫我們分析了使用Hash Match效能最優。

所有查詢方式:

View Code
select ta.* from ta where ta.id not in(select tb.id from tb)
select ta.id from ta where ta.id not in(select tb.id from tb)--Nested Loops
select ta.id from ta left loop join tb on ta.id=tb.id where tb.id is NULL--Nested Loops
select ta.id from ta left merge join tb on ta.id=tb.id where tb.id is NULL--Merge Join
select ta.id from ta left hash join tb on ta.id=tb.id where tb.id is NULL--Hash Match

相關推薦

根據更新另外

#需要更新的表 select distinct owner,table_name from dba_tab_columns t where (t.COLUMN_NAME like '%ACCT_ID%' ) and owner in('COMM'); #根據

MS SQL中複製另外個數據庫中

--複製結構+資料 select * into 資料庫名.dbo.新表名 from 資料庫名.dbo.原表名 select * into Stockholder.dbo.SHInfo from dspring.dbo.HIREMEN --只複製結構

java實現從個數據庫查詢資料經過處理匯入另外個數據庫中

            當資料庫表中有clob欄位或要對錶中資料做較複雜處理時就不太好用指令碼從一個數據庫匯入資料到另外一個數據庫中了,這時就要通過程式碼實現了,下面以orale資料庫為例程式碼如下: import java.sql.Connection; import j

關於平滑遷移Windows下MySQL資料庫從臺電腦到另外臺電腦

目錄 1、使用場景      因為本人最近需要把以前使用的三星膝上型電腦,替換加入固態硬碟和擴充套件了記憶體的ThinkPad電腦,主要原始識公司開始購買的三星本無法擴充套件記憶體條,搞微服務開發,多開幾個服務;記憶體就直接到95%以上了,原來三星

php 根據個數組對另外個數組進行排序問題

現在需要根據keyArr陣列給valueArr陣列進行排序:$keyArr = [100,200,300];$valueArr = [        '200' => 'ni',        '100' => 'hao',        '300' =>

臺電腦同步另外臺電腦時間的指令碼

:A @echo off echo Wscript.sleep 1000 >y.vbs  call y.vbs &del y.vbs net use \\10.23.1.78 "111" /user:"administrator" net time \\10.

sql查詢一個包含另一個的資料,兩種方法。

1、用minus函式的方式:select * from CMN_FUNDwhere FUND_CODE_ in (select FUND_CODE_ from CMN_FUND minus select FUND_CODE_ from CMN_PROMOTION_FUND w

oracle資料庫中使用hibernate生成能正確建立

最近在專案中使用hibernate的動態生成表,即將hbm2ddl.auto配置成update時,發現hibernate並沒有按照預設的生成規則生成相應的資料表資訊。但奇怪的是,只是部分表沒有生成,而其它的表即生成成功了。重新啟動專案,發現問題依舊。奇怪的是,雖然有些表沒有生成,但它相關聯的關聯表即生成了,而

postgresql當存在時刪除及當存在時刪除操作

如果表不存在,而強行去刪除表,SQL會報錯;類似的如果表已經存在而強行去建立同名表,SQL會報錯。需要一種方法安全地刪除和建立表,解決方案的核心在於“exists”關鍵字。 安全地刪除某表(drop

hibernate生成能正確建立的問題

 hibernate在建立表時,在另一個使用者空間中找到了這個表,故不再在當前的使用者空間中建立這個表了。而在建立關聯表時,由於關聯的是本使用者空間的表,故有此錯誤。 hibernate使用了jdbc預設的databasemeta來尋找相應表資料資訊,當使用預設的配置時

解決在oracle資料庫中使用hibernate生成能正確建立的問題

最近在專案中使用hibernate的動態生成表,即將hbm2ddl.auto配置成update時,發現hibernate並沒有按照預設的生成規則生成相應的資料表資訊。但奇怪的是,只是部分表沒有生成,而其它的表即生成成功了。重新啟動專案,發現問題依舊。奇怪的是,雖然有些表沒

查詢另外記錄及效率探究

tro 圖片 刪除 rom 表連接 ren open 方式 mod 在我做項目的時候遇到一個需求,要將存在於表ta而不存在於表tb中的數據查詢出來。 記錄使用的方法和探討效率。 數據準備 創建表ta,並且使用存儲過程插入13000條數據,在我的機器上運行時間: 346.7

查詢另外記錄

參考文獻 http://www.cnblogs.com/xwdreamer/archive/2012/06/01/2530597.html 題目 假如要查詢在a表中存在,但是在b表中不存在的記錄,應該如何查詢。為了便於說明,我們假設a表和b表都只有一個欄位id,a表中的

mysql查詢另外記錄(外連線)

mysql查詢在一張表不在另外一張表的記錄 問題:  查詢一個表(tb1)的欄位記錄不在另一個表(tb2)中      條件:tb1的欄位key的值不在tbl2表中      ----------------------     最原始的寫法:     

Linq實現sql資料存在另外

Linq中包含查詢 //Linq程式碼: T_WxMaterials.Where(n=>T_VideoMsgs.Select(m=>m.MediaID).Contains(n.MediaID)) //生成的sql語句: SELECT [t0].[ID], [t0].[

查詢結果insert到另外

如果要插入目標表不存在: select * into 目標表 from 表 where 條件 如果要插入目標表已經存在: insert into 目的表 select * from 表

查詢的資料插入到另中,分為兩種情況,種是目標存在,另種是目標存在。

         情況一(目標表不存在,建立表名為t1的表,將person表中全部資料插入): createtablet1 asselect* fromperson;情況二(目標表t1存在,將per

Mysql 把查詢的資料插入另外

直接上sql語句: INSERT INTO tableA (name,addDate) SELECT name,addDate from tableB 今天遇到個問題,就是把一個表的資料匯入到另外一張

MySql 從查詢的資料賦值給另外的欄位(MySQL Update Query using a left join)

舉慄: 我們的使用者積分出現重複資料,然後我們要把重複資料刪除掉,重新計算使用者總積分,假設所有積分都是增加的積分。 使用者積分表test_user_points 使用者iduser_id 使用者積分總

Postgresql 資料在中存在,另滿足完整性的查詢

有兩張表T1,T2,表結構和資料如下:create table t1 ( id int ); create table t2 ( id int, finished int ); insert into t1 values (1); insert into t