Как запросить, существует ли схема базы данных

В рамках процесса сборки мы запускаем сценарий обновления базы данных по мере развертывания кода в 4 различных средах. Кроме того, поскольку один и тот же запрос будет добавляться до тех пор, пока мы не введем выпуск в производство, он имеет возможность выполнять несколько раз в данной базе данных. Нравится:

IF NOT EXISTS (SELECT * FROM sys.tables WHERE object_id = OBJECT_ID(N'[Table]'))
BEGIN
  CREATE TABLE [Table]
  (...)
END

В настоящее время у меня есть оператор создания схемы в сценарии развертывания / сборки. Где мне узнать о существовании схемы?


person Pulsehead    schedule 22.10.2008    source источник
comment
Пожалуйста, подумайте об изменении принятого ответа. Невозможно, чтобы принятый вами ответ действительно работал у вас в том виде, в котором он был написан.   -  person Aaron Bertrand    schedule 05.09.2014


Ответы (5)


Вы ищете sys.schemas?

IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'jim')
BEGIN
EXEC('CREATE SCHEMA jim')
END

Обратите внимание, что CREATE SCHEMA должен запускаться в отдельном пакете (согласно ответу ниже)

person bdukes    schedule 22.10.2008
comment
Черт ... за то время, которое мне потребовалось, чтобы отредактировать сообщение, чтобы сделать его более читаемым ... вы устранили мою проблему. Спасибо, мучо! - person Pulsehead; 22.10.2008
comment
это не работает в SQL 2008, потому что CREATE SCHEMA должен быть первым оператором в пакете, см. сообщение vfilby для обходного пути - person sergiom; 30.03.2010
comment
Вы можете использовать «Выбрать 1 из sys.schemas» для повышения производительности. - person vijaysylvester; 26.11.2012
comment
@vijaysylvester Нет, это миф. SQL Server оптимизирует список столбцов, поэтому не имеет значения, что вы туда помещаете. Полностью игнорируется. Хотите доказательств? Положите SELECT 1/0... - person Aaron Bertrand; 05.09.2014
comment
И да, другой ответ, получивший более высокую оценку, должен быть тем, который будет принят. Это не работает так, как написано. - person Aaron Bertrand; 05.09.2014
comment
Я обновил этот ответ, чтобы он не был неправильным (т.е. для использования скрипта ниже stackoverflow.com/a/521271/2688) - person bdukes; 31.01.2015
comment
Хотя * vs 1 vs 1/0 может не иметь никакого значения в производительности, в некоторых случаях это имеет значение. С точки зрения безопасности, все 3 варианта требуют, чтобы у вас был доступ ко всем столбцам, в то время как присвоение имени конкретному столбцу приводит к проверке только столбцов, фактически названных в запросе. Таким образом, 'select col-with-access ...' будет успешным, а 'select 1 ...' не будет, если какой-либо столбец любой таблицы в запросе будет отклонен. - person bielawski; 13.05.2019

@bdukes имеет право на определение того, существует ли схема, но приведенный выше оператор не будет работать в SQL Server 2005. CREATE SCHEMA <name> необходимо запускать в собственном пакете. Обходной путь - выполнить оператор CREATE SCHEMA в exec.

Вот что я использовал в своих сценариях сборки:

IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = '<name>')
BEGIN
    -- The schema must be run in its own batch!
    EXEC( 'CREATE SCHEMA <name>' );
END
person vfilby    schedule 06.02.2009
comment
работает как шарм! это даже позволяет мне помещать свои операторы печати и все такое. - person Tony; 17.06.2014

Это устарело, поэтому я чувствую себя обязанным добавить: Для SQL SERVER 2008+ Все они работают (для выбранной части), затем используйте EXECUTE('CREATE SCHEMA <name>'), чтобы фактически создать его при отрицательных результатах.

DECLARE @schemaName sysname = 'myfunschema';
-- shortest
If EXISTS (SELECT 1 WHERE SCHEMA_ID(@schemaName) IS NOT NULL)
PRINT 'YEA'
ELSE
PRINT 'NOPE'

SELECT DB_NAME() AS dbname WHERE SCHEMA_ID(@schemaName) IS NOT NULL -- nothing returned if not there

IF NOT EXISTS ( SELECT  top 1 *
                FROM    sys.schemas
                WHERE   name = @schemaName )
PRINT 'WOOPS MISSING'
ELSE
PRINT 'Has Schema'

SELECT SCHEMA_NAME(SCHEMA_ID(@schemaName)) AS SchemaName1 -- null if not there otherwise schema name returned

SELECT SCHEMA_ID(@schemaName) AS SchemaID1-- null if not there otherwise schema id returned


IF EXISTS (
    SELECT sd.SchemaExists 
    FROM (
        SELECT 
            CASE 
                WHEN SCHEMA_ID(@schemaName) IS NULL THEN 0
                WHEN SCHEMA_ID(@schemaName) IS NOT NULL THEN 1
                ELSE 0 
            END AS SchemaExists
    ) AS sd
    WHERE sd.SchemaExists = 1
)
BEGIN
    SELECT 'Got it';
END
ELSE
BEGIN
    SELECT 'Schema Missing';
END
person Mark Schultheiss    schedule 15.03.2019
comment
IF schema_id ('MySchemaName') IS NULL работает хорошо и кажется немного более удобным, чем принятый ответ. - person BradC; 10.10.2019
comment
Согласен @BradC. Для тех, кто получает исключение: IF SCHEMA_ID ('out') IS NULL EXEC ('CREATE SCHEMA [out] AUTHORIZATION [out]'); - person Juozas; 16.09.2020

Чтобы быть дополнительной «защитной», следующая версия генерирует ошибку преобразования типа, чтобы учесть возможность (хотя и маловероятную)> 1 совпадения Schema, аналогично тому, как код проверки часто намеренно выбрасывает исключение, потому что я считаю, что это хорошо, и я считаю, что это «лучшая практика» - учитывать все возможные результаты возврата, однако маловероятные, и даже если это просто создание фатального исключения, потому что известные эффекты остановки обработки обычно лучше, чем неизвестные каскадные эффекты невыявленных ошибок . Поскольку это маловероятно, я не думал, что стоит тратить силы на отдельную Count проверку + Throw или _4 _-_ 5 _-_ 6_, чтобы сгенерировать более удобную для пользователя фатальную ошибку, но, тем не менее, фатальную ошибку.

SS 2005-:

declare @HasSchemaX bit
set @HasSchemaX = case (select count(1) from sys.schemas where lower(name) = lower('SchemaX')) when 1 then 1 when 0 then 0 else 'ERROR' end

SS 2008+:

declare @HasSchemaX bit = case (select count(1) from sys.schemas where lower(name) = lower('SchemaX')) when 1 then 1 when 0 then 0 else 'ERROR' end

Потом:

if @HasSchemaX = 1
begin
   ...
end -- if @HasSchemaX = 1
person Tom    schedule 22.06.2017
comment
Я полагаю, что возможно иметь более одной подходящей схемы, когда вы используете сортировку с учетом регистра, но ваша обработка ошибок приведет к следующей ошибке: Ошибка преобразования при преобразовании значения varchar 'ERROR' в тип данных int. - person user247702; 24.10.2017
comment
@Stijn: Это по дизайну похоже на то, как код проверки часто преднамеренно Throw Exception. Как вы сказали, это «маловероятно», поэтому ИМХО, не стоит проводить целую _3 _-_ 4_ или отдельную Count проверку, чтобы сгенерировать более удобную для пользователя фатальную ошибку, но, тем не менее, мне, вероятно, нужна фатальная ошибка. Я верю и считаю, что это «лучшая практика» - учитывать все возможные результаты возврата, какими бы маловероятными они ни были, и даже если это просто создание фатального исключения, потому что известные эффекты остановки обработки обычно лучше, чем неизвестные каскадные эффекты невыявленных ошибок. - person Tom; 25.10.2017
comment
Все это звучит нормально, я не был уверен, было ли это намеренно :) Ваш ответ мог бы выиграть от некоторых дополнительных объяснений, таких как вы только что дали в своем комментарии. - person user247702; 25.10.2017
comment
@Stijn: Моя любимая мозоль - это распространенная не очень "лучшая практика", заключающаяся в том, что я не проверяю, возвращено ли / повлияло ли выражение Select, Insert, Update или Delete больше или меньше, чем ожидаемое количество строк, хотя маловероятно . Даже если есть (есть) Unique Index, которые в настоящее время обеспечивают ожидаемое количество (т.е. 1) строк, которые будут возвращены / затронуты, это может измениться (случайно или (недальновидно) «намеренно») в будущем. - person Tom; 25.10.2017

Если расположение компонентов позволяет, это тоже работает.

IF EXISTS (SELECT 1 FROM sys.schemas WHERE name = 'myschema') SET NOEXEC ON 
go
CREATE SCHEMA myschema
GO 
SET NOEXEC OFF -- if any further processing is needed.
GO
person benik9    schedule 09.01.2020