1. 程式人生 > 其它 >注意!SQL中的NULL

注意!SQL中的NULL

技術標籤:資料分析mysqlsql大資料數學建模

大家好,我是寶器!

越發覺得取數之前的“預處理”非常重要,其中最核心的一點是檢查資料的準確性。大的方向有兩種,其一,確認資料本身無錯亂,其二,保障取數業務邏輯準確。

第一種比較繁瑣、耗時,但是好處理(習慣對結果做一下統計值分佈可以減少很多異常)。第二種不是SQL執行過程中報錯,而是返回的結果和你需要的不太一樣。今天主要聊一下取數分析中容易忽略的點,尤其是SQL中的NULL值。

1、空值JOIN時導致資料丟失

建立案例資料表
CREATETABLEIFNOTEXISTStmp_test_3
(
id_1INT,
col_1VARCHAR(255),
col_2VARCHAR(255)
);


CREATETABLEIFNOTEXISTStmp_test_4
(
id_2INT,
col_3VARCHAR(255),
col_4VARCHAR(255)
);


INSERTINTOtmp_test_3(id_1,col_1,col_2)VALUES(1,'a',null);
INSERTINTOtmp_test_3(id_1,col_1,col_2)VALUES(2,'b','join_key_1');
INSERTINTOtmp_test_3(id_1,col_1,col_2)VALUES(3,'c','join_key_2');


INSERTINTOtmp_test_4(id_2,col_3,col_4)VALUES(1,'a',null);
INSERTINTOtmp_test_4(id_2,col_3,col_4)VALUES(2,'b','join_key_1');
INSERTINTOtmp_test_4(id_2,col_3,col_4)VALUES(3,'c','join_key_2');

檢視下tmp_test_3、tmp_test_4兩個案例表的資料(分佈是類似的)

現在有個業務,部分資料存在tmp_test_3表,有一些存在tmp_test_4表,假設要得到兩個表中的資料,需要這兩個表按col_2、col_4列JOIN連線。

SELECT
*
FROM
tmp_test_3t_a
LeftJOIN
tmp_test_4t_b
on
t_a.col_2=t_b.col_4;

執行一下上面的語句,會得到什麼結果。

結果顯示是col_2和col_4為空的資料是丟失了的。

為什麼?

直接說原因:在tmp_test_3和tmp_test_4表中用於join的列存在NULL值,而NULL和任何值做比較都是返回的NULL(即不能對NULL進行!=、=、>、<等判斷,返回是NULL)。

Coalesce真香函式,將空值替換成一個預設值。

SELECT
*
FROM
tmp_test_3t_a
JOIN
tmp_test_4t_b
on
COALESCE(t_a.col_2,'aaa')=COALESCE(t_b.col_4,'aaa')

這樣就可以把tmp_test_3中包含NULL的資料記錄和tmp_test_4表中的NULL資料記錄JOIN起來。但是這裡有個小問題是他會把這些NULL記錄全部匹配,所以實際應用中可以按照業務需求來做取捨。

2、聚合運算時遇到NULL值

以下是教導主任的302班學生數學成績表,對應了學生名字和成績。

CREATETABLEIFNOTEXISTStmp_score_baoqi_1
(
col_nameVARCHAR(255),
col_coreint
);

INSERTINTOtmp_score_baoqi_1(col_name,col_core)VALUES('a',null);
INSERTINTOtmp_score_baoqi_1(col_name,col_core)VALUES('b',86);
INSERTINTOtmp_score_baoqi_1(col_name,col_core)VALUES('c',78);
INSERTINTOtmp_score_baoqi_1(col_name,col_core)VALUES('d',65);

你驗證資料的時候發現有學生a的成績是空的(沒參加考試),心裡美滋滋的預處理並且開始執行如下指令碼。

SELECT
avg(IFNULL(col_core,0))
FROM
tmp_score_baoqi_1

--返回57.2500

結果返回:這學期教導主任的302班學生數學平均成績是57.25分,四捨五入為58分,不及格。

很好,執行結果也出來了,也不報錯,但是教導主任卻生氣了,質疑怎麼可能他的班上學生數學成績不及格,需要你核查。

經過排查你發現,原來你做預處理的時候把沒參加考試的學生a缺少的數學成績也算在內,用數值0代替NULL,嚴重影響了最終成績。

這個小例子想說明的就是做聚合運算時要注意NULL值,一定要清楚count、sum、avg函式對NULL的處理:

avg

SELECT
avg(col_core),avg(IFNULL(col_core,0))
FROM
tmp_score_baoqi_1

--返回76.33、57.2500

count

SELECT
count(1),count(*),count(col_core)
FROM
tmp_score_baoqi_1

--返回4、4、3

sum:可以對單個列求和,也可以對多個列運算後求和忽略NULL值,且當對多個列運算求和時,如果運算的列中任意一列的值為NULL,則忽略這行的記錄。

補充一條,DISTINCT、ORDER BY、GROUP BY 遇到NULL值視為相等,較好理解,不做資料測試。

請務必注意細節,大概率能決定成敗,本節完。

·················END·················

歡迎長按掃碼關注「資料管道」