有没有人知道如何使用存储相同类型信息的列检查所有数据库表的变量?我有一个设计糟糕的数据库,它将ssn存储在一个数据库中的60多个表中。各种表中列的一些变体包括:
app_ssn
ca_ssn
cand_ssn
crl_ssn
cu_ssn
emtaddr_ssn
re_ssn
sfcart_ssn
sfordr_ssn
socsecno
SSN
SSN
SSN
我想创建一个接受一个值的存储过程,并对每个名称中包含'ssn'的表进行检查。是否有人知道如何执行此操作?
答案 0 :(得分:0)
您需要做的是进行一些研究。但这是你可以开始的地方;
SELECT tbl.NAME AS TableName
,cl.NAME AS ColumnName
,IDENTITY(INT, 1, 1) AS ID
INTO #ColumnsToLoop
FROM sys.tables tbl
JOIN sys.columns cl ON cl.object_id = tbl.object_id
这将为您提供表/列关系,然后您可以根据上面查询中的每一行(基本上循环它)构建一个动态SQL字符串,并使用EXEC或sp_execsql。基本上就是这样;
DECLARE @Loop int = (select min(ID) From #ColumnsToLoop),@MX int = (Select MAX(ID) From #ColumnsToLoop)
WHILE(@Loop<=@MX)
BEGIN
DECLARE @SQL nvarchar(MAX) = 'SQL String'
//Construct the dynamic SQL String
EXEC(@SQL);
SET @Loop += 1
END
答案 1 :(得分:0)
- 我假设表/列名称不需要用方括号括起来。您可能希望在表中保存匹配项 - 我只需选择它们。我还假设ssn是一个字符。
alter proc proc1
@search1 varchar(500)
as
begin
set nocount on
declare @strsql varchar(500)
declare @curtable sysname
declare @prevtable sysname
declare @column sysname
select top 1 @curtable= table_schema+'.'+table_name, @column=column_name
from INFORMATION_SCHEMA.COLUMNS
where CHARINDEX('ssn',column_name) > 0
order by table_schema+'.'+table_name +column_name
-- make sure that at least one column has ssn in the column name
if @curtable is not null
begin
while (1=1)
begin
set @strsql = 'select * from ' +@curtable +' where '+''''+@search1+''''+ ' = '+@column
print @strsql
- 在ssn中传递的任何匹配都将匹配...
exec (@strsql)
set @prevtable = @curtable+@column
select top 1 @curtable= table_schema+'.'+table_name, @column=column_name
from INFORMATION_SCHEMA.COLUMNS
where CHARINDEX('ssn',column_name) > 0
and table_schema+'.'+table_name +column_name> @prevtable
order by table_schema+'.'+table_name +column_name
-- when we run out of columns that contain ssn we are done...
if @@ROWCOUNT = 0
break
end
end
end
答案 2 :(得分:0)
也许我对这个有点过于疯狂,但请告诉我。我认为最好使用表名搜索结果的主键,以便您可以将其加入到表中。我还设法在没有单个游标或循环的情况下完成它。
DECLARE @SSN VARCHAR(25) = '%99%',
@SQL VARCHAR(MAX);
WITH CTE_PrimaryKeys
AS
(
SELECT TABLE_CATALOG,
TABLE_SCHEMA,
TABLE_NAME,
column_name
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE D
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
),
CTE_Columns
AS
(
SELECT A.*,
CONCAT(A.TABLE_CATALOG,'.',A.TABLE_SCHEMA,'.',A.TABLE_NAME) AS FullTableName,
CASE WHEN B.COLUMN_NAME IS NOT NULL THEN 1 ELSE 0 END AS IsPrimaryKey
FROM INFORMATION_SCHEMA.COLUMNS A
LEFT JOIN CTE_PrimaryKeys B
ON A.TABLE_CATALOG = B.TABLE_CATALOG
AND A.TABLE_SCHEMA = B.TABLE_SCHEMA
AND A.TABLE_NAME = B.TABLE_NAME
AND A.COLUMN_NAME = B.COLUMN_NAME
),
CTE_Select
AS
(
SELECT
'SELECT ' +
--This returns the pk_col casted as Varchar and the table name in another columns
STUFF((SELECT ',CAST(' + COLUMN_NAME + ' AS VARCHAR(MAX)) AS pk_col,''' + B.TABLE_NAME + ''' AS Table_Name'
FROM CTE_Columns B
WHERE A.Table_Name = B.TABLE_NAME
AND B.IsPrimaryKey = 1
FOR XML PATH ('')),1,1,'')
+ ' FROM ' + fullTableName +
--This is where I list the columns where LIKE desired SSN
' WHERE ' +
STUFF((SELECT COLUMN_NAME + ' LIKE ''' + @SSN + ''' OR '
FROM CTE_Columns B
WHERE A.Table_Name = B.TABLE_NAME
--This is where I filter so I only get desired columns
AND (
--Uncomment the Collate if your database is case sensitive
COLUMN_NAME /*COLLATE SQL_Latin1_General_CP1_CI_AS*/ LIKE '%ssn%'
--list your column Names that don't have ssn in them
--OR COLUMN_NAME IN ('col1','col2')
)
FOR XML PATH ('')),1,0,'') AS Selects
FROM CTE_Columns A
GROUP BY A.FullTableName,A.TABLE_NAME
)
--Unioning them all together and getting rid of last trailing "OR "
SELECT @SQL = COALESCE(@sql,'') + SUBSTRING(selects,1,LEN(selects) - 3) + ' UNION ALL ' + CHAR(13) --new line for easier debugging
FROM CTE_Select
WHERE selects IS NOT NULL
--Look at your code
SELECT SUBSTRING(@sql,1,LEN(@sql) - 11)