同時修改某一個數據庫中所有表的所有字段的編碼格式(mysql)

最近在進行源碼的二次開發,突然之間有了一個小的需求,就這麼悄悄的突然出現了。

需求原因就不說了,只說這個怎麼實現的。我是用的是mysql數據庫,其他的略有不同,具體到哪一點就只能具體變化了。

看網上有的說直接把數據庫或者表的編碼做改變就行了,可是這樣對字段來說都沒有影響。想改字段的話,直接對字段進行alter修改。可是把每一個字段寫一遍挺煩人的,於是乎找到了一個語句:

alter table 表名 convert to character set utf8;
可以同時修改這個表的所有字段爲u8,但是想改所有的表難道我要把所有的表名輸入一遍嗎?我那麼懶的人怎麼可能這麼做。就算是花點時間也要找一個一勞永逸的方法。又於是乎,找到了一個查詢所有表名的語句:

select table_name from information_schema.`TABLES` where TABLE_SCHEMA = '數據庫名';

mysql的表信息都保存在了 information_schema 數據庫的 TABLES 表裏面,其中的字段 TABLE_SCHEMA 保存了數據庫名,打開看看就是這樣的:


針對這樣的兩句 sql 進行操作就行了。問題也來了,我得設計一個思路啊。

最先想到的是 把alter語句中表名作爲參數的,而查詢出來的表名作爲變量傳進去,再執行alter語句不就行了嗎?

又於是乎,想到循環這種東西。用到循環的話,那寫個存儲過程吧,在其中聲明變量,弄個循環,查詢的表名賦值給變量,再往alter語句中一傳,美美的。

結果,你妹的,各種報錯!!!!

至於爲什麼,很簡單:我不是太擅長數據庫的操作……,其中的規則也只能一邊做一邊查詢怎麼做。別說,各種百度之後我居然搞了兩種方式實現最初的需求:

A方案: 循環 + 變量賦值 + 動態sql語句拼接執行     和     B方案 :遊標 + 循環 + 變量賦值 + 動態sql語句拼接

沒錯,其中的區別就是有沒有用遊標。可是涉及到的問題就不一樣了。

循環,得有結束條件吧。看看網上的資料,各種條件都是以數字的大小爲條件。當然我的A方案也是這樣的,但是循環體不同。我這查詢的數據中可不涉及數字啊,而且一下子查出來多行,就聲明一個變量(聲明多個也沒用,都是一列對應一個變量)

要麼說知道的多一點總是沒錯的:我每循環一次,不查出來多行,就查出一行,賦給變量去拼接sql執行不就行了。

每次查指定行數,循環時還繼續往下查詢,這不還是專門爲一個關鍵字設計的嘛:limit 。就是它,一般用於分頁查詢所以上面的查詢表名的語句就多了點東西:

select table_name from information_schema.`TABLES` where TABLE_SCHEMA = '數據庫名'limit 起始位置, 每次查詢的數量;
至此我就可以讓聲明的變量被依次賦予所有表的名稱了,到這先把這部分整合下,存儲過程的內容如下:

begin

	DECLARE cnt VARCHAR(100); -- 聲明變量用來記錄查詢出的表名
	DECLARE i int;  -- 循環條件,同時可以用來標記表第幾張表
	set i = 0;

-- 循環開始
	while i < 32 do -- 這裏是32是因爲我的數據庫中表的數量是32,想不寫死可以通過再定義一個變量,動態賦值
		select table_name into @cnt from information_schema.`TABLES` where TABLE_SCHEMA = 'xxx' limit i,1;
		select @cnt; -- mysql的打印語句
		-- 這裏添加 alter 語句
		set i = i + 1;
	end while;  
-- 循環結束,注意分號

end
稍微說明下,其中的變量 i 循環條件的同時,也可以充當 limit 的起始位置;into 關鍵字是把查詢結果賦值給 cnt 變量;32用變量代替就是:聲明一個變量,比如: num,循環開始前:
select count(table_name) into @num from information_schema.`TABLES` where TABLE_SCHEMA = '數據庫名'
這個語句的查詢結果賦值給num,循環條件變成: while i < num do ……即可。

到這可以看到打印出來的該數據庫中的所有表名。那這樣,把之前 alter 語句中的表名替換爲 @cnt 不就完成了嗎?就這樣,我有進坑了。

原因是:標準的 alter 語句中是沒有@這個東西的,而把@去掉的話,它又會認爲我想修改的表名就是 cnt ,而不是變量 cnt 。

所以需要動態拼接sql來執行,完整版

A方案:

begin

	DECLARE cnt VARCHAR(100); -- 聲明變量用來記錄查詢出的表名
	DECLARE i int;  -- 循環條件,同時可以用來標記表第幾張表
	set i = 0;

-- 循環開始
	while i < 32 do -- 這裏是32是因爲我的數據庫中表的數量是32,想不寫死可以通過再定義一個變量,動態賦值
		select table_name into @cnt from information_schema.`TABLES` where TABLE_SCHEMA = '數據庫名' limit i,1;
		-- select @cnt; -- mysql的打印語句
		-- alter table @cnt convert to character set utf8; -- 這一句報錯,必須動態拼接才行
		
		set @sql = concat("alter table ", @cnt, " convert to character set utf8");  -- 拼接,注意語句中的空格
		prepare stmt from @sql;  -- 預處理
			execute stmt;  -- 執行
		deallocate prepare stmt;  -- 釋放

		set i = i + 1;
	end while;  
-- 循環結束,注意分號

end
反正就是這個意思,而帶有遊標的

B方案:

BEGIN


  DECLARE a VARCHAR(100);	-- 定義接收遊標數據的變量 
  DECLARE SQL_FOR_SELECT varchar(500); -- 定義接收遊標數據的變量 
 
  DECLARE done INT DEFAULT FALSE; -- 遍歷數據結束標誌
  DECLARE cur CURSOR FOR (select table_name from information_schema.`TABLES` where TABLE_SCHEMA = 'demo_survey');  -- 遊標
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;  -- 將結束標誌綁定到遊標
 
 -- 打開遊標
  OPEN cur; 
		-- 開始循環(loop循環)
		read_loop: LOOP
			-- 提取遊標裏的數據,這裏只有一個,多個的話也一樣;
			FETCH cur INTO a;
			
			-- 聲明結束的時候
			IF done THEN
				LEAVE read_loop;
			END IF;

			-- 要循環的事件,使用了動態sql拼接alter語句,直接寫的話報錯		
			set SQL_FOR_SELECT = concat("alter table ", a, " convert to character set utf8"); -- 拼接
			set @sql = SQL_FOR_SELECT;  
			prepare stmt from @sql; 	-- 預處理
				execute stmt;  		-- 執行
			deallocate prepare stmt;	-- 釋放prepare

		END LOOP;

  -- 關閉遊標
  CLOSE cur;


END
B方案中用了 loop 循環,這樣我可以學習下不同循環的使用方法嘛。對比兩種方案可以看出來循環條件的不同,而且由於遊標的特性,B方案中的查詢結果不需要limit限制

兩種方案的思路是一樣的,手段不同而已。

當然了,我這個最初的需求很少遇到。

不過裏面用到的東西很多我之前是沒怎麼用過的,所以記錄下。


總結:

1.一次性修改表中所有字段的字符集語句:alter table `表名` convert to character set utf8;

2.查詢某個數據庫中所有表的信息語句:select * from information_schema.`TABLES` where TABLE_SCHEMA = '該數據庫名';

3.查詢結果賦值給變量可以用 into 關鍵字(也有其他的)。遊標中沒有@

4.變量賦值可以不用先聲明,如A方案中的@sql ,直接使用 set @sql = xxx。

5.存儲過程中可以直接使用 alter語句 ,也就是靜態sql語句。但是需要傳遞參數的話,要使用動態sql拼接來執行(小慢,就循環了30多次,就能感覺出來比靜態的慢,可能是因爲我循環的是ddl語句吧)。

6.循環,遊標,動態sql用完之後,都有個結束的語句和分號




LG

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章