如何针对多个数据库表验证变量

时间:2015-04-07 17:52:29

标签: sql-server tsql stored-procedures error-handling

有没有人知道如何使用存储相同类型信息的列检查所有数据库表的变量?我有一个设计糟糕的数据库,它将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'的表进行检查。是否有人知道如何执行此操作?

3 个答案:

答案 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)