sysobjects、information_schema.columns 游標寫法不同IF EXISTS (SELECT 1 FROM sysobjects WHERE Name = 'sp_search' AND xtype = 'P')
DROP PROCEDURE sp_search;
GO
CREATE PROCEDURE sp_search
@table_name VARCHAR(200), -- 目標表名
@condition VARCHAR(100) -- 搜索關鍵字
WITH ENCRYPTION -- 加密定義文本(可選)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @str_sql VARCHAR(8000),
@col_name VARCHAR(100),
@str_cols VARCHAR(8000);
SET @str_cols = '';
-- 1. 獲取表所有列名(排除不適合 LIKE 的類型:image, text, ntext, xml, timestamp 等)
DECLARE cur_cols CURSOR FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table_name
AND DATA_TYPE NOT IN ('text', 'ntext', 'image', 'xml', 'timestamp', 'binary', 'varbinary', 'hierarchyid', 'geometry', 'geography')
AND CHARACTER_MAXIMUM_LENGTH IS NOT NULL; -- 僅字符串類型
OPEN cur_cols;
FETCH NEXT FROM cur_cols INTO @col_name;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 2. 構建 OR 連接的 LIKE 條件:col LIKE '%keyword%'
SET @str_cols = @str_cols + @col_name + ' LIKE ''%' + @condition + '%'' OR ';
FETCH NEXT FROM cur_cols INTO @col_name;
END
CLOSE cur_cols;
DEALLOCATE cur_cols;
-- 3. 移除尾部多餘的 ' OR '
IF LEN(@str_cols) > 0
SET @str_cols = LEFT(@str_cols, LEN(@str_cols) - 4);
-- 4. 構建動態 SQL
IF LEN(@str_cols) > 0
BEGIN
SET @str_sql = 'SELECT * FROM ' + QUOTENAME(@table_name) + ' WHERE ' + @str_cols;
-- PRINT @str_sql; -- 調試用
EXEC (@str_sql);
END
ELSE
BEGIN
-- 無可搜索列時返回空結果集
SET @str_sql = 'SELECT * FROM ' + QUOTENAME(@table_name) + ' WHERE 1=0';
EXEC (@str_sql);
END
END;
GO
INFORMATION_SCHEMA.COLUMNS:標準元數據視圖,跨數據庫可移植OR 條件QUOTENAME():防止表名注入,自動加 [] 括號LIKE 報錯WITH ENCRYPTION:隱藏過程定義(非強加密,僅混淆)-- 搜索 Users 表中包含 'john' 的所有字符串列
EXEC sp_search 'Users', 'john';
-- 等效動態生成 SQL(假設 Users 有 name, email, phone, address 列):
SELECT * FROM [Users] WHERE
[name] LIKE '%john%' OR
[email] LIKE '%john%' OR
[phone] LIKE '%john%' OR
[address] LIKE '%john%';
MySQL 存儲過程語法不同,需調整:
DELIMITER $$
DROP PROCEDURE IF EXISTS `sp_search` $$
CREATE PROCEDURE `sp_search`(IN p_table_name VARCHAR(64), IN p_condition VARCHAR(100))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_col_name VARCHAR(64);
DECLARE v_where_clause TEXT DEFAULT '';
DECLARE v_sql TEXT;
DECLARE cur CURSOR FOR
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = p_table_name
AND DATA_TYPE IN ('char','varchar','text','tinytext','mediumtext','longtext');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_col_name;
IF done THEN LEAVE read_loop; END IF;
SET v_where_clause = CONCAT(v_where_clause, '`', v_col_name, '` LIKE ', QUOTE(CONCAT('%', p_condition, '%')), ' OR ');
END LOOP;
CLOSE cur;
IF LENGTH(v_where_clause) > 0 THEN
SET v_where_clause = LEFT(v_where_clause, LENGTH(v_where_clause) - 4);
SET v_sql = CONCAT('SELECT * FROM `', p_table_name, '` WHERE ', v_where_clause);
SET @sql = v_sql;
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
ELSE
SELECT * FROM `p_table_name` WHERE 1=0;
END IF;
END $$
DELIMITER ;
FULLTEXT、SQL Server FULLTEXT CATALOG、Elasticsearch/OpenSearchQUOTE()/QUOTENAME() 處理關鍵字,表名仍有風險,建議白名單校驗OFFSET ... ROWS FETCH NEXT ... ROWS ONLY (SQL Server 2012+) 或 LIMIT (MySQL)通用模糊查詢存儲過程利用元數據動態構建 LIKE 條件,實現「一個接口搜全表」。但其本質是**全表掃描**,性能不可控。**生產環境僅作為輔助/後台工具**,核心業務搜索必須使用專業全文搜索引擎或數據庫原生全文索引。