Come interrogare se esiste uno schema di database


98

Come parte del nostro processo di compilazione, eseguiamo uno script di aggiornamento del database mentre distribuiamo il codice in 4 ambienti diversi. Inoltre, poiché la stessa query verrà aggiunta fino a quando non rilasciamo una versione in produzione, deve essere in grado di essere eseguita più volte su un determinato database. Come questo:

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

Attualmente ho un'istruzione di creazione dello schema nello script di distribuzione / compilazione. Dove chiedo l'esistenza di uno schema?


2
Si prega di considerare di modificare la risposta accettata. Non è possibile che la risposta che hai accettato abbia effettivamente funzionato per te come scritta.
— Aaron Bertrand,

Risposte:


165

Stai cercando sys.schemas ?

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

Nota che CREATE SCHEMAdeve essere eseguito nel proprio batch (secondo la risposta di seguito )


Maledizione ... nel tempo che mi ci è voluto per modificare il post per renderlo più leggibile ... hai risolto il mio problema. Grazie mucho!
— Pulsehead

18
questo non funziona in SQL 2008 perché CREATE SCHEMA deve essere la prima istruzione in un batch, vedere il post di vfilby per una soluzione alternativa
— sergiom

4
È possibile utilizzare "Seleziona 1 da sys.schemas" per migliorare le prestazioni.
— vijaysylvester

4
@vijaysylvester No, questo è un mito. SQL Server ottimizza l'elenco delle colonne, quindi non importa cosa ci metti. Completamente ignorato. Vuoi una prova? PutSELECT 1/0...
— Aaron Bertrand

1
Ho aggiornato questa risposta di non essere corretto (cioè utilizzare lo script dal basso stackoverflow.com/a/521271/2688 )
— bdukes

157

@bdukes ha ragione per determinare se lo schema esiste, ma la dichiarazione di cui sopra non funzionerà in SQL Server 2005. CREATE SCHEMA <name>deve essere eseguita nel proprio batch. Una soluzione è eseguire l' CREATE SCHEMAistruzione in un exec.

Ecco cosa ho usato nei miei script di build:

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

funziona come un fascino! questo mi permette anche di mettere le mie dichiarazioni stampate e tutto il resto.
— Tony

2

Questo è vecchio quindi mi sento in dovere di aggiungere: Per SQL SERVER 2008+ Funzionano tutti (per la parte selezionata), quindi utilizzarli EXECUTE('CREATE SCHEMA <name>')per crearli effettivamente con risultati negativi.

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 NULLfunziona bene e sembra un po 'più conveniente della risposta accettata.
— BradC

1

Solo per essere più "difensivo", la seguente versione genera un errore di conversione del tipo per tenere conto della possibilità (per quanto improbabile) di corrispondenze> 1 Schemasimili a come il codice di convalida spesso lancia intenzionalmente le eccezioni perché credo che sia buono e credo che lo sia "'best practice'" per tenere conto di tutti i possibili risultati di ritorno, per quanto improbabili e anche se si tratta solo di generare un'eccezione fatale perché gli effetti noti dell'interruzione dell'elaborazione sono generalmente migliori degli effetti a cascata sconosciuti di errori non intrappolati. Poiché è altamente improbabile, non ho pensato che valesse la pena di un Countcontrollo separato + Throwo Try- Catch- Throwper generare un errore fatale più user-friendly ma comunque un errore fatale.

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

Poi:

if @HasSchemaX = 1
begin
   ...
end -- if @HasSchemaX = 1

Suppongo che sia possibile avere più di uno schema corrispondente quando si utilizzano regole di confronto con distinzione tra maiuscole e minuscole, ma la "gestione degli errori" comporterà il seguente errore: Conversione non riuscita durante la conversione del valore varchar "ERROR" nel tipo di dati int.
— user247702

@Stijn: Questo è "By Design" simile a come il codice di validazione è spesso intenzionalmente Throw Exception. Come hai detto tu, non è " 'probabile'" per accadere, quindi IMHO, non valeva la pena nel suo complesso Try- Catcho separati Countdi controllo per generare un errore fatale più user-friendly, ma a prescindere, avrei probabilmente vuole un errore fatale. Credo in e credo che sia "la migliore pratica" tenere conto di tutti i possibili risultati di ritorno per quanto improbabili e anche se si tratta solo di generare un'eccezione fatale perché gli effetti noti dell'arresto dell'elaborazione sono generalmente migliori degli effetti a cascata sconosciuti di un-trapped errori.
— Tom

Sembra tutto a posto, non ero sicuro che fosse intenzionale :) La tua risposta potrebbe beneficiare di qualche spiegazione aggiuntiva, come hai appena fornito nel tuo commento.
— user247702

@Stijn: Il mio piccolo cruccio è il comune non così " 'best practice'" di non controllare se un Select, Insert, Updateo DeleteStatement restituito / colpito più o meno del previsto # di righe però improbabili. Anche se ci sono Unique Indexattualmente garanzie che il numero previsto (cioè 1) di righe verrà restituito / influenzato, ciò potrebbe cambiare (accidentalmente o (miope) "'intenzionalmente'") in futuro.
— Tom

1

Se il layout dei componenti lo consente, funziona anche questo.

SE ESISTE (SELEZIONA 1 DA sys.schemas WHERE name = 'myschema') ATTIVA NOEXEC 
partire
CREATE SCHEMA myschema
PARTIRE 
IMPOSTARE NOEXEC OFF - se è necessaria un'ulteriore elaborazione.
PARTIRE
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.