Як мені запитати, чи існує схема бази даних


98

В рамках нашого процесу побудови ми запускаємо сценарій оновлення бази даних, коли ми розгортаємо код у 4 різних середовищах. Далі, так як той же запит буде додаватися до того, поки ми не впустити випуск у виробництво він повинен мати можливість запускати кілька разів на дану базі даних. Подобається це:

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

На даний момент у мене є оператор створення схеми у сценарії розгортання / збірки. Де я можу запитати наявність схеми?


2
Будь ласка, подумайте про зміну прийнятої відповіді. Неможливо, щоб прийнята вами відповідь насправді працювала для вас, як написана.
Аарон Бертран,

Відповіді:


165

Шукаєте sys.schemas ?

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

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


Боже ... за той час, що мені знадобився редагувати допис, щоб зробити його більш читабельним ... ти вирішив мою проблему. Спасибі мучо!
Pulsehead,

18
це не працює в SQL 2008, оскільки СТВОРИТИ СХЕМУ має бути першим оператором у пакеті, див. пост vfilby щодо обхідного
шляху

4
Ви можете використовувати "Вибрати 1 із sys.schemas" для покращення продуктивності.
vijaysylvester

4
@vijaysylvester Ні, це міф. SQL Server оптимізує список стовпців, тому не має значення, що ви там помістили. Повністю ігнорується. Хочете доказів? ПутSELECT 1/0...
Аарон Бертран

1
Я оновив ця відповідь не може бути неправильно (тобто використовувати скрипт з нижче stackoverflow.com/a/521271/2688 )
bdukes

157

@bdukes має право на гроші, щоб визначити, чи існує схема, але наведене вище твердження не буде працювати в SQL Server 2005. CREATE SCHEMA <name>потрібно запускати у власному пакеті. Навколо потрібно виконати CREATE SCHEMAоператор у виконанні.

Ось те, що я використав у своїх скриптах збірки:

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

працює як шарм! це навіть дозволяє мені розміщувати свої друковані виписки та все.
Тоні,

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. Як ви вже сказали, це не "" ймовірно "", тому IMHO, це не коштувало цілого Try- Catchабо окремої Countперевірки, щоб створити більш зручну фатальну помилку, але незалежно від цього, я, швидше за все, хотів би мати фатальну помилку. Я вірю і вважаю, що "найкраща практика" враховувати всі можливі результати повернення, проте малоймовірно, навіть якщо це просто генерує фатальне виняток, оскільки відомі ефекти зупинки обробки зазвичай кращі, ніж невідомі каскадні ефекти незахопленого помилки.
Том,

Все це звучить нормально, я не був впевнений, чи це було навмисно :) Ваша відповідь може отримати користь від додаткового пояснення, як ви щойно дали у своєму коментарі.
user247702

@Stijn: Моя улюблена мозоль є спільною не так «найкращою практикою» з не перевіряти , якщо Select, Insert, Updateабо Deleteзаяву повернуто / постраждалі більш або менш , ніж очікувалося # рядків , однак навряд чи. Навіть якщо є (є) Unique Indexв даний момент, що забезпечує очікуваний номер (тобто 1) рядків, які потрібно повернути / вплинути, це може змінитися (випадково чи (короткозоро)) "навмисно" "в майбутньому.
Том

1

Якщо компонування компонентів дозволяє це, це теж працює.

ЯКЩО ІСНУЄ (ВИБЕРІТЬ 1 З sys.schemas ДЕ name = 'myschema') ВСТАНОВИТИ NOEXEC ON 
йти
СТВОРИТИ СХЕМУ myschema
ПОВЕРНУТИСЯ 
ВСТАНОВИТИ NOEXEC OFF - якщо потрібна подальша обробка.
ПОВЕРНУТИСЯ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.