SQL在一个表中所有列查询某个值
使用场景:知道表名,同时知道这个表中含有某个字符串,但是不知道这个字符串是在表的哪些列,在列比较多的情况下,查询很麻烦,通过以下语句或者封装的存储可以查出字符串在哪些列出现。结果集里 ContainsValue = 1 就是包含字符串的列。
-- 配置参数
DECLARE @TableName NVARCHAR(128) = 'YourTableName'; -- 替换为实际表名
DECLARE @SearchValue SQL_VARIANT = 'YourSearchValue'; -- 替换为要查找的值
DECLARE @SQL NVARCHAR(MAX) = '';
DECLARE @ColumnName NVARCHAR(128);
DECLARE @ColumnType NVARCHAR(128);
DECLARE @SearchValueStr NVARCHAR(MAX);
DECLARE @IsNumeric BIT;
DECLARE @IsDate BIT;
-- 创建临时表存储结果
IF OBJECT_ID('tempdb..#ColumnSearchResults') IS NOT NULL
DROP TABLE #ColumnSearchResults;
CREATE TABLE #ColumnSearchResults (
ColumnName NVARCHAR(128),
ContainsValue BIT
);
-- 将SQL_VARIANT转换为字符串
SET @SearchValueStr = CONVERT(NVARCHAR(MAX), @SearchValue);
-- 预检查是否为数值或日期
SET @IsNumeric = ISNUMERIC(@SearchValueStr);
SET @IsDate = ISDATE(@SearchValueStr);
-- 获取表的所有列名(兼容旧版SQL Server)
DECLARE ColumnCursor CURSOR FOR
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND DATA_TYPE NOT IN ('image', 'text', 'ntext', 'hierarchyid', 'geometry', 'geography', 'xml', 'timestamp');
OPEN ColumnCursor;
FETCH NEXT FROM ColumnCursor INTO @ColumnName, @ColumnType;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 处理数值类型(优化算术溢出问题)
IF @ColumnType IN ('int', 'bigint', 'smallint', 'tinyint', 'decimal', 'numeric', 'float', 'real', 'money', 'smallmoney')
BEGIN
IF @IsNumeric = 1
BEGIN
-- 使用字符串比较避免直接转换搜索值
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), ' + QUOTENAME(@ColumnName) + '))) = @SearchValue)
THEN 1
ELSE 0
END';
END
ELSE
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''', 0';
END
-- 处理日期/时间类型的特殊转换
ELSE IF @ColumnType IN ('date', 'datetime', 'datetime2', 'smalldatetime')
BEGIN
IF @IsDate = 1
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE CONVERT(NVARCHAR(30), ' + QUOTENAME(@ColumnName) + ', 120) = @SearchValue)
THEN 1
ELSE 0
END';
ELSE
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''', 0';
END
-- 处理时间类型
ELSE IF @ColumnType = 'time'
BEGIN
-- 检查时间格式是否有效
IF @IsDate = 1 OR ISDATE('2000-01-01 ' + @SearchValueStr) = 1
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE CONVERT(NVARCHAR(12), ' + QUOTENAME(@ColumnName) + ', 114) = @SearchValue)
THEN 1
ELSE 0
END';
ELSE
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''', 0';
END
-- 处理位类型
ELSE IF @ColumnType = 'bit'
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE ' + QUOTENAME(@ColumnName) + ' = CASE
WHEN @SearchValue IN (''1'', ''true'', ''TRUE'') THEN 1
WHEN @SearchValue IN (''0'', ''false'', ''FALSE'') THEN 0
ELSE NULL
END)
THEN 1
ELSE 0
END';
-- 处理其他类型(默认作为字符串比较)
ELSE
SET @SQL = '
INSERT INTO #ColumnSearchResults (ColumnName, ContainsValue)
SELECT ''' + QUOTENAME(@ColumnName) + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE ' + QUOTENAME(@ColumnName) + ' = @SearchValue)
THEN 1
ELSE 0
END';
-- 执行查询
EXEC sp_executesql
@SQL,
N'@SearchValue NVARCHAR(MAX)',
@SearchValue = @SearchValueStr;
FETCH NEXT FROM ColumnCursor INTO @ColumnName, @ColumnType;
END;
CLOSE ColumnCursor;
DEALLOCATE ColumnCursor;
-- 返回结果
SELECT * FROM #ColumnSearchResults
-- 封装为存储过程
CREATE PROCEDURE UP_SearchAllColumns
@TableName NVARCHAR(128),
@SearchValue SQL_VARIANT,
@ResultTable NVARCHAR(128) = NULL -- 可选参数:指定结果表名
AS
BEGIN
SET NOCOUNT ON;
-- 声明变量
DECLARE @SQL NVARCHAR(MAX) = '';
DECLARE @ColumnName NVARCHAR(128);
DECLARE @ColumnType NVARCHAR(128);
DECLARE @SearchValueStr NVARCHAR(MAX);
DECLARE @IsNumeric BIT;
DECLARE @IsDate BIT;
DECLARE @ResultTableName NVARCHAR(128);
-- 设置结果表名
IF @ResultTable IS NULL
SET @ResultTableName = '##SearchResults_' + REPLACE(CAST(NEWID() AS NVARCHAR(36)), '-', '_');
ELSE
SET @ResultTableName = @ResultTable;
-- 创建结果表
SET @SQL = '
IF OBJECT_ID(''tempdb..' + QUOTENAME(@ResultTableName) + ''') IS NOT NULL
DROP TABLE ' + QUOTENAME(@ResultTableName) + ';
CREATE TABLE ' + QUOTENAME(@ResultTableName) + ' (
ColumnName NVARCHAR(128),
ContainsValue BIT
);';
EXEC sp_executesql @SQL;
-- 将SQL_VARIANT转换为字符串
SET @SearchValueStr = CONVERT(NVARCHAR(MAX), @SearchValue);
-- 预检查是否为数值或日期
SET @IsNumeric = ISNUMERIC(@SearchValueStr);
SET @IsDate = ISDATE(@SearchValueStr);
-- 检查目标表是否存在
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName)
BEGIN
RAISERROR('目标表不存在: %s', 16, 1, @TableName);
RETURN;
END;
-- 获取表的所有列名(兼容旧版SQL Server)
DECLARE ColumnCursor CURSOR FOR
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @TableName
AND DATA_TYPE NOT IN ('image', 'text', 'ntext', 'hierarchyid', 'geometry', 'geography', 'xml', 'timestamp');
OPEN ColumnCursor;
FETCH NEXT FROM ColumnCursor INTO @ColumnName, @ColumnType;
WHILE @@FETCH_STATUS = 0
BEGIN
-- 处理数值类型(优化算术溢出问题)
IF @ColumnType IN ('int', 'bigint', 'smallint', 'tinyint', 'decimal', 'numeric', 'float', 'real', 'money', 'smallmoney')
BEGIN
IF @IsNumeric = 1
BEGIN
-- 使用字符串比较避免直接转换搜索值
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE LTRIM(RTRIM(CONVERT(NVARCHAR(MAX), ' + QUOTENAME(@ColumnName) + '))) = @pSearchValue)
THEN 1
ELSE 0
END';
END
ELSE
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''', 0';
END
-- 处理日期/时间类型的特殊转换
ELSE IF @ColumnType IN ('date', 'datetime', 'datetime2', 'smalldatetime')
BEGIN
IF @IsDate = 1
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE CONVERT(NVARCHAR(30), ' + QUOTENAME(@ColumnName) + ', 120) = @pSearchValue)
THEN 1
ELSE 0
END';
ELSE
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''', 0';
END
-- 处理时间类型
ELSE IF @ColumnType = 'time'
BEGIN
-- 检查时间格式是否有效
IF @IsDate = 1 OR ISDATE('2000-01-01 ' + @SearchValueStr) = 1
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE CONVERT(NVARCHAR(12), ' + QUOTENAME(@ColumnName) + ', 114) = @pSearchValue)
THEN 1
ELSE 0
END';
ELSE
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''', 0';
END
-- 处理位类型
ELSE IF @ColumnType = 'bit'
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE ' + QUOTENAME(@ColumnName) + ' = CASE
WHEN @pSearchValue IN (''1'', ''true'', ''TRUE'') THEN 1
WHEN @pSearchValue IN (''0'', ''false'', ''FALSE'') THEN 0
ELSE NULL
END)
THEN 1
ELSE 0
END';
-- 处理其他类型(默认作为字符串比较)
ELSE
SET @SQL = '
INSERT INTO ' + QUOTENAME(@ResultTableName) + ' (ColumnName, ContainsValue)
SELECT ''' + REPLACE(@ColumnName, '''', '''''') + ''',
CASE
WHEN EXISTS (
SELECT 1
FROM ' + QUOTENAME(@TableName) + '
WHERE ' + QUOTENAME(@ColumnName) + ' = @pSearchValue)
THEN 1
ELSE 0
END';
-- 执行查询
BEGIN TRY
EXEC sp_executesql
@SQL,
N'@pSearchValue NVARCHAR(MAX)',
@pSearchValue = @SearchValueStr;
END TRY
BEGIN CATCH
-- 记录错误但继续处理其他列
PRINT '处理列 [' + @ColumnName + '] 时出错: ' + ERROR_MESSAGE();
END CATCH;
FETCH NEXT FROM ColumnCursor INTO @ColumnName, @ColumnType;
END;
CLOSE ColumnCursor;
DEALLOCATE ColumnCursor;
-- 返回结果
SET @SQL = 'SELECT * FROM ' + QUOTENAME(@ResultTableName);
EXEC sp_executesql @SQL;
-- 如果使用的是临时表,则清理
IF @ResultTable IS NULL
BEGIN
SET @SQL = 'DROP TABLE ' + QUOTENAME(@ResultTableName);
EXEC sp_executesql @SQL;
END;
END;
/*
-- 简单调用(使用临时表)
EXEC up_SearchAllColumns
@TableName = 'YourTableName', -- 实际表名
@SearchValue = 'YourSearchValue'; -- 实际要查询的值
-- 指定结果表
EXEC up_SearchAllColumns
@TableName = 'YourTableName',
@SearchValue = 'YourSearchValue',
@ResultTable = 'dbo.SearchResults';
-- 查看结果
SELECT * FROM dbo.SearchResults;
*/