Wie frage ich ab, ob ein Datenbankschema vorhanden ist?

98

Als Teil unseres Erstellungsprozesses führen wir ein Datenbankaktualisierungsskript aus, während wir Code in 4 verschiedenen Umgebungen bereitstellen. Da dieselbe Abfrage hinzugefügt wird, bis eine Version in die Produktion aufgenommen wird , muss sie in einer bestimmten Datenbank mehrmals ausgeführt werden können. So was:

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

Derzeit habe ich eine Erstellungsschema-Anweisung im Bereitstellungs- / Erstellungsskript. Wo frage ich nach der Existenz eines Schemas?

Pulsehead
quelle
2
Bitte ändern Sie die akzeptierte Antwort. Es ist nicht möglich, dass die von Ihnen akzeptierte Antwort tatsächlich wie geschrieben für Sie funktioniert hat.
Aaron Bertrand

Antworten:

165

Suchen Sie nach sys.schemas ?

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

Beachten Sie, dass das CREATE SCHEMAin einem eigenen Stapel ausgeführt werden muss (gemäß der Antwort unten ).

bdukes
quelle
Verdammt ... in der Zeit, in der ich den Beitrag bearbeitet habe, um ihn besser lesbar zu machen ... haben Sie mein Problem behoben. Vielen Dank!
Pulsehead
18
Dies funktioniert in SQL 2008 nicht, da das CREATE SCHEMA die erste Anweisung in einem Stapel sein muss. Eine Problemumgehung finden Sie im vfilby-Beitrag
Sergiom
4
Sie können 'Select 1 from sys.schemas' verwenden, um die Leistung zu verbessern.
Vijaysylvester
4
@ Vijaysylvester Nein, das ist ein Mythos. SQL Server optimiert die Spaltenliste, sodass es keine Rolle spielt, was Sie dort ablegen. Völlig ignoriert. Willst du Beweise? PutSELECT 1/0...
Aaron Bertrand
1
Ich habe diese Antwort aktualisiert, um nicht falsch zu sein (dh das Skript von unten zu verwenden stackoverflow.com/a/521271/2688 )
bdukes
157

@bdukes ist genau richtig, um festzustellen, ob das Schema vorhanden ist, aber die obige Anweisung funktioniert in SQL Server 2005 nicht. Sie CREATE SCHEMA <name>muss in einem eigenen Stapel ausgeführt werden. Eine Problemumgehung besteht darin, die CREATE SCHEMAAnweisung in einer Ausführung auszuführen .

Folgendes habe ich in meinen Build-Skripten verwendet:

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
quelle
klappt wunderbar! Dadurch kann ich sogar meine Druckanweisungen und alles einfügen.
Tony
2

Dies ist alt, daher fühle ich mich gezwungen hinzuzufügen: Für SQL SERVER 2008+ Diese funktionieren alle (für den ausgewählten Teil) und werden dann verwendet EXECUTE('CREATE SCHEMA <name>'), um sie tatsächlich bei negativen Ergebnissen zu erstellen.

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
Mark Schultheiss
quelle
IF schema_id ('MySchemaName') IS NULLfunktioniert gut und scheint ein bisschen bequemer als die akzeptierte Antwort.
BradC
1

Um besonders "defensiv" zu sein, generiert die folgende Version einen Typkonvertierungsfehler, um die Möglichkeit (jedoch unwahrscheinlich) von> 1 Übereinstimmungen zu berücksichtigen Schema, ähnlich wie Validierungscode häufig absichtlich Ausnahmen auslöst, weil ich glaube, dass dies gut ist und ich glaube, dass dies der Fall ist "'Best Practice'", um alle möglichen Rückgabeergebnisse zu berücksichtigen, jedoch unwahrscheinlich und selbst wenn es sich nur um eine schwerwiegende Ausnahme handelt, da die bekannten Auswirkungen des Stoppens der Verarbeitung normalerweise besser sind als die unbekannten Kaskadeneffekte nicht eingeschlossener Fehler. Da dies höchst unwahrscheinlich ist, hielt ich es nicht für sinnvoll, einen separaten CountCheck + Throwoder Try- Catch- Throwdurchzuführen, um einen benutzerfreundlicheren schwerwiegenden Fehler zu generieren, der jedoch immer noch schwerwiegend ist.

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

Dann:

if @HasSchemaX = 1
begin
   ...
end -- if @HasSchemaX = 1
Tom
quelle
Ich nehme an, es ist möglich, mehr als ein übereinstimmendes Schema zu haben, wenn Sie eine Sortierung verwenden, bei der zwischen Groß- und Kleinschreibung unterschieden wird, aber Ihre "Fehlerbehandlung" führt zu folgendem Fehler: Die Konvertierung ist fehlgeschlagen, wenn der varchar-Wert 'ERROR' in den Datentyp int konvertiert wurde.
user247702
@Stijn: Das ist "By Design", ähnlich wie Validierungscode oft absichtlich Throw Exception. Wie Sie sagten, ist es nicht "wahrscheinlich", also war es meiner Meinung nach kein Ganzes wert Try- Catchoder eine separate CountÜberprüfung, um einen benutzerfreundlicheren schwerwiegenden Fehler zu generieren, aber unabhängig davon würde ich wahrscheinlich einen schwerwiegenden Fehler wünschen. Ich glaube an und ich glaube, es ist "Best Practice", alle möglichen Rückgabeergebnisse zu berücksichtigen, auch wenn dies unwahrscheinlich ist und selbst wenn dies nur eine fatale Ausnahme darstellt, da die bekannten Auswirkungen des Stoppens der Verarbeitung normalerweise besser sind als die unbekannten Kaskadeneffekte von nicht eingeschlossenen Daten Fehler.
Tom
Das klingt alles in Ordnung, ich war mir nicht sicher, ob es beabsichtigt war :) Ihre Antwort könnte von einer zusätzlichen Erklärung profitieren, wie Sie sie gerade in Ihrem Kommentar gegeben haben.
user247702
@Stijn: Mein Haustier peeve ist das gemeinsame nicht-so „‚best practice‘“ nicht überprüft , ob ein Select, Insert, Updateoder DeleteStatement mehr zurück / betroffen oder weniger als die erwarteten Anzahl der Zeilen jedoch unwahrscheinlich. Selbst wenn Unique Indexderzeit sichergestellt wird, dass die erwartete Anzahl (dh 1) der zurückzugebenden / betroffenen Zeilen zurückgegeben wird, könnte sich dies (versehentlich oder (kurzsichtig) "absichtlich") in Zukunft ändern.
Tom
1

Wenn das Layout der Komponenten dies zulässt, funktioniert dies auch.

WENN EXISTIERT (SELECT 1 FROM sys.schemas WHERE name = 'myschema') SETZE NOEXEC ON 
gehen
SCHEMA ERSTELLEN myschema
GEHEN 
NOEXEC AUSSETZEN - wenn eine weitere Verarbeitung erforderlich ist.
GEHEN
benik9
quelle