目錄
我如何才能從查詢中獲取非空字段?是的,您可以使用現代的編程語言輕鬆完成此操作,但是通過從表中獲取冗餘信息可能會浪費資源,而且很多時候,它可能會添加冗餘代碼。從5.3版開始,此任務僅面向MySQL。
介紹
您擁有大量的信息,其中包含大量的電子表格,csv,xml,bin,日誌或純文本文件,並且經過簡化後,表中有幾列沒有值,當然也沒有NULL 值。對於桌面用戶,這可能只是一個煩惱。另一方面,對於雲用戶,您可能沒有便宜的資源,而成本僅需支付少量賬單。對於DBA,那些NULL佔很大空間,它們沒有數據。但是事實是,ETL作業僅帶來數據,而在此無罪。出於教學目的,本文使用非常流行的MySQL數據庫引擎解決了這種情況。
背景
我藉助一個基於流視頻商店服務公司的名爲cinemashop的數據庫,給出了這種情況的示例。它在MySQL上運行,但對於MariaDB和Percona分支也將起作用。這些方面的工作可以從這裏進一步推進。
使用代碼
在cinemashop數據庫內部,有一個包含幾列的customer表,因爲行大小可以放在那裏(到目前爲止,超過1000列)。
MySQL ETL作業將信息放在此處,僅需要從無null值的列中獲取數據。下圖顯示了前幾個寄存器的一小部分:
因此,值得檢查該字段中的所有寄存器是否至少僅具有一個數據。僅此一項數據就可以改變數據湖/數據倉庫/報告服務輸入的模型,可能佔總人口的1%。由於這種情況,下面叫check_field_null的存儲過程產生此行爲。該存儲過程使用PREPARE,EXECUTE以及DEALLOCATE語句來管理SQL動態。它將COUNT標量函數的結果存儲在QN變量中。因此,有可能獲得多少個寄存器是NULL值的值。
/*======================================================
Classroom: SQL Level 3
Database: cinemashop
======================================================*/
use cinemashop;
drop procedure if exists check_field_null;
set delimiter //
create procedure check_field_null(col varchar(64), schemaname varchar(255), _
tablename varchar(255), out QN int)
BEGIN
SET @sSQL = concat('SELECT @N := COUNT(*) FROM ', schemaname, '.', _
tablename , ' WHERE (', col, ' <=> NULL);');
prepare stm from @sSQL;
execute stm;
set QN =@N;
deallocate prepare stm;
END
//
set delimiter ;
下面的代碼說明了上述功能的作用。關於customer_id字段,它表明存在值。
set @p = 0;
call check_field_null('customer_id', 'cinemashop', 'customer', @p);
/* This field customer_id has NOT null values */
select @p;
另一方面,如果像這樣的字段gender僅具有NULL值,則計數器將檢查預期結果:
set @p = 0;
call check_field_null('gender', 'cinemashop', 'customer', @p);
/* This field gender has null values */
select @p;
最後,工作包括獲取表中各列的字段名稱。今天,它可能是一個數據結構,但是明天,它可能會按需更改,並且當然可以在那裏顯示NULL值。這種方式在稱爲cur_cs_customer的存儲過程中使用了CURSOR技術。它僅在information_schema允許提取時纔有效,因此,那裏需要一些權限。請注意,Count_Null變量的使用方式與之前的p變量相同。同樣,allcols變量將MYCOL變量中每列的所有字段存儲爲沒有任何NULL值。
/*======================================================
Classroom: SQL Level 3
Database: cinemashop
Table name: customer
======================================================*/
use cinemashop;
drop procedure if exists cur_cs_customer;
set delimiter //
create procedure cur_cs_customer(inout allcols varchar(255))
BEGIN
DECLARE Count_Null int default 0;
DECLARE initial INT DEFAULT 0;
DECLARE MYCOL char(64);
DECLARE ch_done INT DEFAULT 0;
DECLARE cs_cur1 CURSOR FOR SELECT C.COLUMN_NAME
FROM information_schema.COLUMNS C
WHERE C.TABLE_SCHEMA = 'cinemashop' _
AND C.TABLE_NAME ='customer';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET ch_done = true;
open cs_cur1;
read_cs_cur1:
LOOP
FETCH cs_cur1 INTO MYCOL;
IF (ch_done ) THEN
LEAVE read_cs_cur1;
END IF;
IF NOT isnull(MYCOL) THEN
call check_field_null(MYCOL, 'cinemashop', 'customer', Count_Null);
if Count_Null = 0 then
/* Only it includes fields with not null values */
set initial = initial + 1;
if initial = 1 then
SET allcols = MYCOL;
else
SET allcols = concat( cast(allcols as char(255)), ',', MYCOL);
end if;
end if;
END IF;
END LOOP read_cs_cur1;
close cs_cur1;
select allcols;
END
//
放在一起,我們可以使用非交互式語句使用@my_args變量,例如所有沒有NULL值的列中的string。
set delimiter ;
call cur_cs_customer(@my_args);
select @my_args;
set @stm = concat('SELECT ', @my_args, ' FROM cinemashop.customer;');
PREPARE stmt1 FROM @stm;
execute stmt1;
deallocate prepare stmt1;
進程運行時,將獲得以下輸出:
當然,可以使用動態SQL創建cur_cs_customer存儲過程以供一般使用,但是稍後我們可能會檢查此存儲過程。我目前的目的只是獲得第一解決方案。
興趣點
MySQL不是我最喜歡的數據庫引擎,但是由於使用Web開發中許多編程語言的簡單性,許多大型網站都具有RDBMS。另外,我的工作重點是平臺集成,其中cookbook有一些ETL、數據倉庫、數據管道、數據湖、數據中心的任務,當然,還有用於數據挖掘和數據科學任務的數據庫。