使用動態SQL處理table_name作為輸入參數的存儲過程(MySQL)

来源:https://www.cnblogs.com/leohahah/archive/2019/09/27/11596900.html
-Advertisement-
Play Games

關於mysql如何創建和使用存儲過程,參考筆記《MySQL存儲過程和函數創建》以及官網:https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html 本篇主要示例使用了輸入參數的存儲過程,並解決使用表名作為輸入參數的問題,因為之前遇到過需 ...


關於mysql如何創建和使用存儲過程,參考筆記《MySQL存儲過程和函數創建》以及官網:https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html

本篇主要示例使用了輸入參數的存儲過程,並解決使用表名作為輸入參數的問題,因為之前遇到過需要使用表名作為參數的存儲過程,很難處理。

問題描述:

假設我們有TEST1-TEST12共12個相同結構的車輛里程錶,我們想要對這12個表進行去重,那麼邏輯上比較簡單的辦法是寫12個存儲過程處理或者寫一個存儲過程每執行一次改一次表名並重新編譯,但是這樣都太麻煩了。

接下來很容易的就會想到是否可以使用表名作為輸入參數,這樣每次執行給定表名即可。

因此初始的存儲過程代碼如下:

DELIMITER //
DROP PROCEDURE IF EXISTS Del_Dupilicate;
CREATE DEFINER=`root`@`localhost` PROCEDURE `Del_Dupilicate`(in table_name varchar(64))
BEGIN
DECLARE v_min_id,v_group_count INT;
DECLARE v_get_on_time,v_get_off_time DATETIME;
DECLARE v_car_no VARCHAR(255);
DECLARE done INT DEFAULT FALSE;
DECLARE my_cur CURSOR FOR SELECT get_on_time,get_off_time,car_no,min(id),count(1) AS count FROM table_name GROUP BY get_on_time,get_off_time,car_no HAVING count>1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN my_cur;
myloop: LOOP
FETCH my_cur INTO v_get_on_time,v_get_off_time,v_car_no,v_min_id,v_group_count;
IF done THEN
LEAVE myloop;
END IF;
DELETE FROM table_name WHERE get_on_time=v_get_on_time AND get_off_time=v_get_off_time AND car_no=v_car_no AND id>v_min_id;
COMMIT;
END LOOP;
CLOSE my_cur;
END;
//
DELIMITER ;

上述存儲過程可以正常編譯,但是執行卻一定會報table not exist的錯誤,因為mysql會錯誤的把輸入變數table_name當做真正的資料庫表名,這顯然是錯誤的。

那麼如何在SQL中引用變數呢?一個可行的辦法是使用動態SQL,把變數拼入SQL語句中然後執行動態SQL。

所以根據官網(https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html)提供的語法,對於上述procedure中的delete語句可以改寫成如下格式:

set @del_sql=concat('DELETE FROM ',table_name,' WHERE get_on_time=',v_get_on_time,' AND get_off_time=',v_get_off_time,' AND car_no=',v_car_no,' AND id>',v_min_id)
PREPARE stmt FROM @del_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
//註意prepare目前只能在存儲過程中使用,函數和觸發器都不適用。

Ps:需要註意的是官網在示例prepare的語法時使用了?作為占位符,但是經試驗?不能作為表名的占位符(實際上官網只示例了?可以作為整數字面量的占位符,我猜測凡是資料庫對象用?作為占位符都會報錯),想要將表名變數整合入SQL中只能使用concat函數,concat的函數的輸入支持local variables、user defined variables和input variables。

好,delete語句處理完畢,但是對於cursor中的select語句呢?官網明確說明游標中不能使用動態SQL,也就是不能使用prepare語句,那隻能換一種思路了。

游標的作用是什麼呢?是獲取一個結果集以便進行遍歷,那麼可否使用臨時表代替游標來存儲結果集,這樣可以使用動態SQL創建臨時表(mysql的臨時表是session級別的,不同會話可以使用相同名稱的臨時表,會話釋放時臨時表自動刪除):

set @tmp_table_name=concat(table_name,'_tmp');
set @cur_sql=concat('create temporary table ',@tmp_table_name,' as select get_on_time,get_off_time,car_no,min(id) as min_id,count(1) AS count FROM ',table_name,' GROUP BY get_on_time,get_off_time,car_no HAVING count>1');
PREPARE stmt FROM @cur_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
然後整個存儲過程的邏輯就可以更改了,因為我們把中間結果集存入了臨時表,那就無需遍歷cursor了,同時連declare的local variables也省了(因為這些本地變數是用於遍歷游標時存儲列值的),只需要delete ... join即可,因此最終的存儲過程修改為:
CREATE DEFINER=`root`@`localhost` PROCEDURE `Del_Dupilicate`(in table_name varchar(64))
BEGIN

set @tmp_table_name=concat(table_name,'_tmp');

set @cur_sql=concat('create temporary table ',@tmp_table_name,' as select get_on_time,get_off_time,car_no,min(id) as min_id,count(1) AS count FROM ',table_name,' GROUP BY get_on_time,get_off_time,car_no HAVING count>1');
PREPARE stmt FROM @cur_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

set @del_sql=concat('delete a from ',table_name,' a join ',@tmp_table_name,' b on a.get_on_time=b.get_on_time and a.get_off_time=b.get_off_time and a.car_no=b.car_no and a.id != b.min_id');
PREPARE stmt FROM @del_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

set @drop_tmp_sql=concat('drop temporary table ',@tmp_table_name);
PREPARE stmt FROM @drop_tmp_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

END
 調用:
call Del_Dupilicate('TEST1');
 上述存儲過程經過了實測,可以正常的刪除重覆數據。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • NN與2NN工作機制 思考:NameNode中的元數據是存儲在哪裡的? 假設存儲在NameNode節點的硬碟中,因為經常需要隨機訪問和響應客戶請求,必然效率太低,所以是存儲在記憶體中的 但是,如果存儲在記憶體中,一旦斷電,元數據丟失,整個集群便無法工作,因此會在硬碟中產生備份元數據的Fsimage 但是 ...
  • HDFS 基於流數據模式訪問和處理超大文件的需求而開發的。 低延時的數據訪問 HDFS是為高吞吐數據傳輸設計的,因此可能犧牲延時HBase更適合低延時的數據訪問。 大量小文件 文件的元數據保存在NameNode的記憶體中, 整個文件系統的文件數量會受限於NameNode的記憶體大小。 多方讀寫,需要任意 ...
  • ETL概述 ETL(Extraction-Transformation-Loading)是將業務系統的數據經過抽取、清洗轉換之後載入到數據倉庫的過程,目的是將企業中的分散、零亂、標準不統一的數據整合到一起,為企業的決策提供分析依據, ETL是BI(商業智能)項目重要的一個環節。 數據治理流程 數據挖 ...
  • 1.幾個簡單的基本的sql語句 ...
  • 本文主要記錄了在使用MySQL的過程中遇到錯誤代碼為1728的問題以及解決方案。 ...
  • 1、平衡: 性能 容量 成本 2、高可用(主節點高可用): 節點 網路 磁碟 3、部署方案: Master和Standby Master分機部署 primaty segment 與miiror Segment分機部署 Segment Mirror 方案: Group Miirroring Spead ...
  • 在SQL Server中,如何找到一張表或某個索引擁有那些頁面(page)呢? 有時候,我們在分析和研究(例如,死鎖分析)的時候還真有這樣的需求,那麼如何做呢? SQL Server 2012提供了一個無文檔的DMF(sys.dm_db_database_page_allocations)可以實現我... ...
  • 本文主要記錄了在使用MySQL的過程中導入導出許可權設置時遇到的問題以及解決方案。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...