Как мне перечислить все таблицы во всех базах данных в SQL Server в одном наборе результатов? - PullRequest
57 голосов
/ 20 мая 2010

Я ищу код T-SQL для перечисления всех таблиц во всех базах данных в SQL Server (по крайней мере, в SS2005 и SS2008; было бы неплохо также применить к SS2000). Однако суть в том, что мне хотелось бы один набор результатов . Это исключает отличный ответ от Пинал Дэйв :

sp_msforeachdb 'select "?" AS db, * from [?].sys.tables'

Вышеупомянутый сохраненный процесс генерирует один набор результатов для базы данных , что хорошо, если вы находитесь в IDE, такой как SSMS, которая может отображать несколько наборов результатов. Однако мне нужен один набор результатов, потому что мне нужен запрос, который по сути является инструментом «поиска»: если я добавлю предложение, подобное WHERE tablename like '%accounts', тогда оно сообщит мне, где найти таблицы BillAccounts, ClientAccounts и VendorAccounts, независимо от того, какой База данных, в которой они находятся.


2010.05.20 Обновление, примерно через 20 минут ...

Пока что ответ Ремуса выглядит наиболее интересным. Вместо того, чтобы публиковать это как ответ и присуждаю его самому себе, я публикую здесь его версию, которую я изменил, чтобы включить имя БД и пример фильтра. Похоже, что Ремус получит кредит за ответ, но на данный момент!

declare @sql nvarchar(max);
set @sql = N'select b.name as "DB", a.name collate Latin1_General_CI_AI as "Table", object_id, schema_id, cast(1 as int) as database_id  from master.sys.tables a join sys.databases b on database_id=1 where a.name like ''account%''';

select @sql = @sql + N' union all select b.name as "DB", a.name collate Latin1_General_CI_AI, object_id, schema_id, ' + cast(database_id as nvarchar(10)) + N' from ' + quotename(name) + N'.sys.tables a join sys.databases b on database_id=' + cast(database_id as nvarchar(10)) + 'where a.name like ''account%'''
from sys.databases where database_id > 1 

and state = 0
and user_access = 0;

exec sp_executesql @sql;

2010.05.24 Обновление - Новый Фронтнер!

Отзывы и ответы были отличными. Дальнейшее совместное участие привело к появлению нового лидера : ответ КМ от 21 мая!

Вот проблемы, которые я обнаружил с помощью решения Remus:

Основная проблема: Пользователи имеют разные разрешения, что приводит к успешному выполнению запроса на основе данных (т. Е. Значения фильтрации). Запустить мою производственную базу данных с фильтрацией no (т.е. без предложения WHERE) Я получил эту ошибку на нескольких БД, к которым у меня нет прав доступа:

Основной сервер "msorens" не может получить доступ к базе данных. «ETLprocDB» в текущем контексте безопасности.

Запрос будет успешным с некоторыми пунктами фильтрации - теми, которые не касаются БД вне моего уровня доступа.

Незначительная проблема: Нелегко разложить на поддержку SQL Server 2000 (да, некоторые из нас все еще используют его ...), потому что он строит одну строку при накоплении записей для каждой базы данных. С моей системой я превысил отметку в 8000 символов около 40 баз данных.

Незначительная проблема: Дублирующий код - настройка цикла по существу дублирует тело цикла. Я понимаю обоснование, но это просто моя любимая мозоль ...

Ответ КМ не затронут этими вопросами. Хранимая процедура sp_msforeachdb учитывает права пользователя, что позволяет избежать проблем с разрешениями. Я еще не пробовал код с SS2000, но KM указывает на корректировки, которые должны это сделать.

Я публикую следующие изменения в ответе КМ, исходя из моих личных предпочтений. В частности:

  • Я удалил имя сервера, так как оно ничего не добавляет в результирующий набор.
  • Я разбил компоненты имени на их собственные поля в наборе результатов (имя базы данных, имя схемы и имя таблицы).
  • Я ввел отдельные фильтры для каждого из трех полей.
  • Я добавил сортировку по трем полям (которые можно изменить в соответствии с вашими предпочтениями).

Вот моя модификация кода KM (с примером фильтра, примененного только к имени таблицы):

SET NOCOUNT ON
DECLARE @AllTables table (DbName sysname,SchemaName sysname, TableName sysname)
DECLARE
     @SearchDb nvarchar(200)
    ,@SearchSchema nvarchar(200)
    ,@SearchTable nvarchar(200)
    ,@SQL nvarchar(4000)
SET @SearchDb='%'
SET @SearchSchema='%'
SET @SearchTable='%Account%'
SET @SQL='select ''?'' as DbName, s.name as SchemaName, t.name as TableName from [?].sys.tables t inner join sys.schemas s on t.schema_id=s.schema_id WHERE ''?'' LIKE '''+@SearchDb+''' AND s.name LIKE '''+@SearchSchema+''' AND t.name LIKE '''+@SearchTable+''''

INSERT INTO @AllTables (DbName, SchemaName, TableName)
    EXEC sp_msforeachdb @SQL
SET NOCOUNT OFF
SELECT * FROM @AllTables ORDER BY DbName, SchemaName, TableName

Ответы [ 15 ]

0 голосов
/ 03 октября 2017

Я понимаю, что это очень старый поток, но он был очень полезен, когда мне нужно было собрать системную документацию для нескольких разных серверов, на которых размещались разные версии Sql Server.Я закончил тем, что создал 4 хранимых процедуры, которые я публикую здесь для пользы сообщества.Мы используем Dynamics NAV, поэтому две хранимые процедуры с NAV в имени выделяют компанию Nav из имени таблицы.Наслаждайтесь ...

2 из 4 - ListServerDatabaseTables

USE [YourDatabase]
GO

SET QUOTED_IDENTIFIER ON
GO

ALTER PROC [dbo].[ListServerDatabaseTables]
(
    @SearchDatabases varchar(max) = NULL,  
    @SearchSchema sysname = NULL,
    @SearchTables varchar(max) = NULL,
    @ExcludeSystemDatabases bit = 1,
    @Sql varchar(max) OUTPUT
)
AS BEGIN

/**************************************************************************************************************************************
* Lists all of the database tables for a given server.
*   Parameters
*       SearchDatabases - Comma delimited list of database names for which to search - converted into series of Like statements
*                         Defaults to null  
*       SearchSchema - Schema name for which to search
*                      Defaults to null 
*       SearchTables - Comma delimited list of table names for which to search - converted into series of Like statements
*                      Defaults to null 
*       ExcludeSystemDatabases - 1 to exclude system databases, otherwise 0
*                          Defaults to 1
*       Sql - Output - the stored proc generated sql
*
*   Adapted from answer by KM answered May 21 '10 at 13:33
*   From: How do I list all tables in all databases in SQL Server in a single result set?
*   Link: /2089792/kak-mne-perechislit-vse-tablitsy-vo-vseh-bazah-dannyh-v-sql-server-v-odnom-nabore-rezultatov
*
**************************************************************************************************************************************/

    SET NOCOUNT ON

    DECLARE @l_CompoundLikeStatement varchar(max) = ''
    DECLARE @l_TableName sysname
    DECLARE @l_DatabaseName sysname

    DECLARE @l_Index int

    DECLARE @l_UseAndText bit = 0

    DECLARE @AllTables table (ServerName sysname, DbName sysname, SchemaName sysname, TableName sysname)

    SET @Sql = 
        'select @@ServerName as ''ServerName'', ''?'' as ''DbName'', s.name as ''SchemaName'', t.name as ''TableName'' ' + char(13) +
        'from [?].sys.tables t inner join ' + char(13) + 
        '     sys.schemas s on t.schema_id = s.schema_id '

    -- Comma delimited list of database names for which to search
    IF @SearchDatabases IS NOT NULL BEGIN
        SET @l_CompoundLikeStatement = char(13) + 'where (' + char(13)
        WHILE LEN(LTRIM(RTRIM(@SearchDatabases))) > 0 BEGIN
            SET @l_Index = CHARINDEX(',', @SearchDatabases)
            IF @l_Index = 0 BEGIN
                SET @l_DatabaseName = LTRIM(RTRIM(@SearchDatabases))
            END ELSE BEGIN
                SET @l_DatabaseName = LTRIM(RTRIM(LEFT(@SearchDatabases, @l_Index - 1)))
            END

            SET @SearchDatabases = LTRIM(RTRIM(REPLACE(LTRIM(RTRIM(REPLACE(@SearchDatabases, @l_DatabaseName, ''))), ',', '')))
            SET @l_CompoundLikeStatement = @l_CompoundLikeStatement + char(13) + ' ''?'' like ''' + @l_DatabaseName + '%'' COLLATE Latin1_General_CI_AS or '
        END

        -- Trim trailing Or and add closing right parenthesis )
        SET @l_CompoundLikeStatement = LTRIM(RTRIM(@l_CompoundLikeStatement))
        SET @l_CompoundLikeStatement = LEFT(@l_CompoundLikeStatement, LEN(@l_CompoundLikeStatement) - 2) + ')'

        SET @Sql = @Sql + char(13) +
            @l_CompoundLikeStatement

        SET @l_UseAndText = 1
    END

    -- Search schema
    IF @SearchSchema IS NOT NULL BEGIN
        SET @Sql = @Sql + char(13)
        SET @Sql = @Sql + CASE WHEN @l_UseAndText = 1 THEN '  and ' ELSE 'where ' END +
            's.name LIKE ''' + @SearchSchema + ''' COLLATE Latin1_General_CI_AS'
        SET @l_UseAndText = 1
    END

    -- Comma delimited list of table names for which to search
    IF @SearchTables IS NOT NULL BEGIN
        SET @l_CompoundLikeStatement = char(13) + CASE WHEN @l_UseAndText = 1 THEN '  and (' ELSE 'where (' END + char(13) 
        WHILE LEN(LTRIM(RTRIM(@SearchTables))) > 0 BEGIN
            SET @l_Index = CHARINDEX(',', @SearchTables)
            IF @l_Index = 0 BEGIN
                SET @l_TableName = LTRIM(RTRIM(@SearchTables))
            END ELSE BEGIN
                SET @l_TableName = LTRIM(RTRIM(LEFT(@SearchTables, @l_Index - 1)))
            END

            SET @SearchTables = LTRIM(RTRIM(REPLACE(LTRIM(RTRIM(REPLACE(@SearchTables, @l_TableName, ''))), ',', '')))
            SET @l_CompoundLikeStatement = @l_CompoundLikeStatement + char(13) + ' t.name like ''$' + @l_TableName + ''' COLLATE Latin1_General_CI_AS or '
        END

        -- Trim trailing Or and add closing right parenthesis )
        SET @l_CompoundLikeStatement = LTRIM(RTRIM(@l_CompoundLikeStatement))
        SET @l_CompoundLikeStatement = LEFT(@l_CompoundLikeStatement, LEN(@l_CompoundLikeStatement) - 2) + ' )'

        SET @Sql = @Sql + char(13) +
            @l_CompoundLikeStatement

        SET @l_UseAndText = 1
    END

    IF @ExcludeSystemDatabases = 1 BEGIN
        SET @Sql = @Sql + char(13)
        SET @Sql = @Sql + case when @l_UseAndText = 1 THEN '  and ' ELSE 'where ' END +
            '''?'' not in (''master'' COLLATE Latin1_General_CI_AS, ''model'' COLLATE Latin1_General_CI_AS, ''msdb'' COLLATE Latin1_General_CI_AS, ''tempdb'' COLLATE Latin1_General_CI_AS)' 
    END

/*  PRINT @Sql  */

    INSERT INTO @AllTables 
    EXEC sp_msforeachdb @Sql

    SELECT * FROM @AllTables ORDER BY DbName COLLATE Latin1_General_CI_AS, SchemaName COLLATE Latin1_General_CI_AS, TableName COLLATE Latin1_General_CI_AS
END
0 голосов
/ 03 октября 2017

Я понимаю, что это очень старый поток, но он был очень полезен, когда мне пришлось собрать системную документацию для нескольких разных серверов, на которых размещались разные версии Sql Server. Я закончил тем, что создал 4 хранимых процедуры, которые я публикую здесь для пользы сообщества. Мы используем Dynamics NAV, поэтому две хранимые процедуры с NAV в имени выделяют компанию Nav из имени таблицы. Наслаждайтесь ...

1 из 4 - Базы данных ListServer

USE [YourDatabase]
GO

/****** Object:  StoredProcedure [pssi].[ListServerDatabases]    Script Date: 10/3/2017 8:56:45 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROC [dbo].[ListServerDatabases]
(
    @SearchDatabases varchar(max) = NULL,  
    @ExcludeSystemDatabases bit = 1,
    @Sql varchar(max) OUTPUT
)
AS BEGIN

/**************************************************************************************************************************************
* Lists all of the databases for a given server.
*   Parameters
*       SearchDatabases - Comma delimited list of database names for which to search - converted into series of Like statements
*                         Defaults to null  
*       ExcludeSystemDatabases - 1 to exclude system databases, otherwise 0
*                                Defaults to 1
*       Sql - Output - the stored proc generated sql
*
*   Adapted from answer by 
*   From: How do I list all tables in all databases in SQL Server in a single result set?
*   Link: /2089792/kak-mne-perechislit-vse-tablitsy-vo-vseh-bazah-dannyh-v-sql-server-v-odnom-nabore-rezultatov
*
**************************************************************************************************************************************/

    SET NOCOUNT ON

    DECLARE @l_CompoundLikeStatement varchar(max) = ''
    DECLARE @l_DatabaseName sysname

    DECLARE @l_Index int

    DECLARE @lUseAndText bit = 0

    DECLARE @l_AllDatabases table (ServerName sysname, DbName sysname)

    SET @Sql = 
        'select @@ServerName as ''ServerName'', ''?'' as ''DbName'''

    IF @SearchDatabases IS NOT NULL BEGIN
        SET @l_CompoundLikeStatement = char(13) + 'where (' + char(13)
        WHILE LEN(LTRIM(RTRIM(@SearchDatabases))) > 0 BEGIN
            SET @l_Index = CHARINDEX(',', @SearchDatabases)
            IF @l_Index = 0 BEGIN
                SET @l_DatabaseName = LTRIM(RTRIM(@SearchDatabases))
            END ELSE BEGIN
                SET @l_DatabaseName = LTRIM(RTRIM(LEFT(@SearchDatabases, @l_Index - 1)))
            END

            SET @SearchDatabases = LTRIM(RTRIM(REPLACE(LTRIM(RTRIM(REPLACE(@SearchDatabases, @l_DatabaseName, ''))), ',', '')))
            SET @l_CompoundLikeStatement = @l_CompoundLikeStatement + char(13) + ' ''?'' like ''' + @l_DatabaseName + '%'' COLLATE Latin1_General_CI_AS or '
        END

        -- Trim trailing Or and add closing right parenthesis )
        SET @l_CompoundLikeStatement = LTRIM(RTRIM(@l_CompoundLikeStatement))
        SET @l_CompoundLikeStatement = LEFT(@l_CompoundLikeStatement, LEN(@l_CompoundLikeStatement) - 2) + ' )'

        SET @Sql = @Sql + char(13) +
            @l_CompoundLikeStatement

        SET @lUseAndText = 1
    END

    IF @ExcludeSystemDatabases = 1 BEGIN
        SET @Sql = @Sql + char(13)
        SET @Sql = @Sql + case when @lUseAndText = 1 THEN '  and ' ELSE 'where ' END +
            '''?'' not in (''master'' COLLATE Latin1_General_CI_AS, ''model'' COLLATE Latin1_General_CI_AS, ''msdb'' COLLATE Latin1_General_CI_AS, ''tempdb'' COLLATE Latin1_General_CI_AS)' 
    END

/*  PRINT @Sql  */

    INSERT INTO @l_AllDatabases 
    EXEC sp_msforeachdb @Sql

    SELECT * FROM @l_AllDatabases ORDER BY DbName
END
0 голосов
/ 04 апреля 2017

Это действительно удобно, но я хотел показать все пользовательские объекты, а не только таблицы, поэтому я адаптировал его для использования sys.objects вместо sys.tables

SET NOCOUNT ON
DECLARE @AllTables table (DbName sysname,SchemaName sysname, ObjectType char(2), ObjectName sysname)
DECLARE
     @SearchDb nvarchar(200)
    ,@SearchSchema nvarchar(200)
    ,@SearchObject nvarchar(200)
    ,@SQL nvarchar(4000)
SET @SearchDb='%'
SET @SearchSchema='%'
SET @SearchObject='%Something%'
SET @SQL='select ''?'' as DbName, s.name as SchemaName, t.type as ObjectType, t.name as ObjectName 
from [?].sys.objects t inner join sys.schemas s on t.schema_id=s.schema_id 
WHERE t.type in (''FN'',''IF'',''U'',''V'',''P'',''TF'') 
AND ''?'' LIKE '''+@SearchDb+''' 
AND s.name LIKE '''+@SearchSchema+''' 
AND t.name LIKE '''+@SearchObject+''''

INSERT INTO @AllTables (DbName, SchemaName, ObjectType, ObjectName)
    EXEC sp_msforeachdb @SQL
SET NOCOUNT OFF
SELECT * FROM @AllTables ORDER BY DbName, SchemaName, ObjectType, ObjectName
0 голосов
/ 20 мая 2010

Все, что вам нужно сделать, это запустить хранимую процедуру sp_tables. http://msdn.microsoft.com/en-us/library/aa260318(SQL.80).aspx

0 голосов
/ 20 мая 2010

Я почти уверен, что вам придется просмотреть список баз данных, а затем перечислить каждую таблицу. Вы должны быть в состоянии объединить их вместе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...