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

98

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

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

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

Pulsehead
источник
2
Пожалуйста, подумайте об изменении принятого ответа. Невозможно, чтобы принятый вами ответ действительно работал на вас в том виде, в котором он был написан.
Аарон Бертран

Ответы:

165

Вы ищете sys.schemas ?

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

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

Bdukes
источник
Черт ... за время, которое мне потребовалось, чтобы отредактировать сообщение, чтобы сделать его более читабельным ... вы устранили мою проблему. Спасибо, мучо!
Pulsehead,
18
это не работает в SQL 2008, потому что CREATE SCHEMA должен быть первым оператором в пакете, см. сообщение vfilby для обходного пути
sergiom
4
Вы можете использовать «Выбрать 1 из sys.schemas» для повышения производительности.
vijaysylvester
4
@vijaysylvester Нет, это миф. SQL Server оптимизирует список столбцов, поэтому не имеет значения, что вы туда помещаете. Полностью игнорируется. Хотите доказательств? PutSELECT 1/0...
Аарон Бертран
1
Я обновил этот ответ, чтобы он не был неправильным (например, чтобы использовать скрипт ниже stackoverflow.com/a/521271/2688 )
bdukes
157

@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
vfilby
источник
работает как шарм! это даже позволяет мне помещать свои операторы печати и все такое.
Тони
2

Это устарело, поэтому я чувствую себя обязанным добавить: Для 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
Марк Шультайс
источник
IF schema_id ('MySchemaName') IS NULLработает хорошо и кажется немного более удобным, чем принятый ответ.
BradC
1

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

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
Том
источник
Я полагаю, что возможно иметь более одной подходящей схемы при использовании сортировки с учетом регистра, но ваша «обработка ошибок» приведет к следующей ошибке: Ошибка преобразования при преобразовании значения varchar 'ERROR' в тип данных int.
user247702
@Stijn: Это «по дизайну» похоже на то, как часто преднамеренно используется код проверки Throw Exception. Как вы сказали, что это не «„вероятно“ , » должно произойти, так имхо, не стоит в целом Try- Catchили отдельный Countчек , чтобы создать более удобный фатальную ошибку, но независимо от того , я, скорее всего , хочу фатальную ошибку. Я верю и считаю, что это «лучшая практика» - учитывать все возможные результаты возврата, даже если они маловероятны, и даже если это просто приводит к фатальному исключению, потому что известные эффекты остановки обработки обычно лучше, чем неизвестные каскадные эффекты невыловленных ошибки.
Том
Все это звучит нормально, я не был уверен, было ли это намеренно :) Ваш ответ может выиграть от некоторых дополнительных объяснений, таких как вы только что дали в своем комментарии.
user247702
@Stijn: Моя любимая мозоль является общей не так «наилучшей практикой» из не проверять , если Select, Insert, Updateили Deleteзаявление возвращено / пострадавшие более или менее , чем ожидалось # строк , однако вряд ли. Даже если есть (есть) в Unique Indexнастоящее время обеспечение ожидаемого количества (т.е. 1) строк, которые будут возвращены / затронуты, это может измениться (случайно или (недальновидно) «намеренно») в будущем.
Том
1

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

ЕСЛИ СУЩЕСТВУЕТ (ВЫБЕРИТЕ 1 ИЗ sys.schemas, ГДЕ name = 'myschema') УСТАНОВИТЕ NOEXEC ВКЛ. 
идти
СОЗДАТЬ СХЕМУ myschema
ИДТИ 
ВЫКЛЮЧИТЕ NOEXEC - если требуется дальнейшая обработка.
ИДТИ
benik9
источник