Transact SQL(mssql)从SELECT" search"返回DB的名称。

时间:2016-07-21 15:14:42

标签: sql-server

Running Microsoft SQL Server 11.0.3128
on Windows Server 2012 R2 Essentials

我试图根据提供的变量(调用SQL脚本的批处理文件)返回特定数据库的名称。

在我看来,这个过程应该是这样的:

 For each database in instance
       Look in the current database
              Return databasename if variable is found in column

到目前为止,我一直在使用的代码如下所示:

EXEC dbo.sp_MSForeachdb  '  
USE [?];        
SELECT  DB_NAME() AS DBName
        UNION SELECT
            ColumnName
            FROM dbo.Items
            WHERE ColumnName =''variable''
'

问题是,这比我想要的要多得多,因为它返回" null"不包含"变量"的数据库的值并为不包含" ColumnName"。

的数据库创建消息

但我似乎无法弄清楚如何在没有其他东西的情况下获得我想要的具体信息。第一次海报,如果我能改进这个问题,请告诉我。

谢谢!

1 个答案:

答案 0 :(得分:0)

编辑:哎呀,起初你没有意识到你正在使用mssql而不是mysql。以下原则仍然有效;你只需要稍微调整语法并使用用户函数来替换group_concat,因为mssql没有。

这是一种没有sp_MSForeachdb的方法。请注意,您需要首先清理参数。

delimiter $$

create procedure FindDatabases
(
    in varName varchar(2000),
    in tableName varchar(2000),
    in columnName varchar(2000)
)
begin
    declare selectQuery varchar(2000);

    select group_concat(
                concat('select ''', 
                    table_schema, 
                    ''' as DatabaseName from ', 
                    table_schema, 
                    '.',
                    tableName,
                    ' where ',
                    columnName,
                    ' = ''',
                    varName,
                    '''')
                separator ' union ') as DatabaseNames
    from information_schema.tables 
    where table_name = tableName
    into @selectQuery;  

    prepare preparedSql from @selectQuery;
    execute preparedSql;
    deallocate prepare preparedSql;

end $$
delimiter ;

使用示例:

call FindDatabases ( 'variable', 'Items', 'ColumnName' )

此过程为每个数据库生成一个sql查询,其表名与提供的表名相匹配,将它们组合在一起,然后执行它们。如果该数据库中的指定表具有与包含与指定变量名匹配的值的指定名称匹配的列,则union中的每个查询都将返回其数据库名称。只有符合这些要求的数据库才会出现在查询结果中,因此您不必担心结果中的空值。

附加编辑:正如所承诺的,这是一个sqlserver版本。

create procedure FindDatabases
(
    @varName varchar(2000),
    @tableName varchar(2000),
    @columnName varchar(2000)
)
as
begin
    declare @selectQuery nvarchar(2000)


    -- first, get a list of database names that contain the specified table 
    IF OBJECT_ID('tempdb.dbo.#db_temp') IS NOT NULL
        DROP TABLE #db_temp 

    CREATE TABLE #db_temp (DatabaseName SYSNAME)

    SELECT @selectQuery = (
        SELECT '
            USE [' + d.name + ']; 

            INSERT INTO #db_temp (DatabaseName)
            SELECT DB_NAME() as DatabaseName
            WHERE EXISTS(
                SELECT 1
                FROM sys.objects
                WHERE [object_id] = OBJECT_ID(''' + @tableName + ''')
                    AND [type] = ''U''
            )'
        FROM sys.databases d
        WHERE d.name NOT IN ('master', 'tempdb', 'model', 'msdb')
            AND d.state_desc != 'OFFLINE'
        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')

    EXEC sys.sp_executesql @selectQuery

    -- use something like mysql's group_concat function to turn that list into a bunch of  union all select statements
    select
        @selectQuery =
        (
            SELECT LEFT(database_names , LEN(database_names ) - 10) AS     database_names
            FROM #db_temp AS extern
        CROSS APPLY
            (
                SELECT 'select ''' + DatabaseName + ''' as     DatabaseName from ' + DatabaseName + '.dbo.' + @tableName +
                ' where ' + @columnName + ' = ''' + @varName + '''' +     ' union all '
                FROM #db_temp AS intern
                FOR XML PATH('')
            ) pre_trimmed (database_names)
            GROUP BY database_names
        )       

    drop table #db_temp

    -- run those select statements
    exec sp_executesql @selectQuery
end

运行它:

exec FindDatabases 'someVar', 'Items', 'ColumnName'

我无耻地从herehere中删除了一些片段,以解决缺少group_concat函数和sqlserver的information_schema问题,该函数只包含本地数据库的信息,而不是跨数据库共享信息。