¿Cómo consulto si existe un esquema de base de datos?

98

Como parte de nuestro proceso de compilación, ejecutamos un script de actualización de la base de datos mientras implementamos el código en 4 entornos diferentes. Además, puesto que la misma consulta se agregarán hasta que caigamos en un comunicado de producción que tiene que ser capaz de ejecutar varias veces en una base de datos dada. Me gusta esto:

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

Actualmente tengo una declaración de esquema de creación en el script de implementación / compilación. ¿Dónde consulto la existencia de un esquema?

Pulsehead
fuente
2
Considere cambiar la respuesta aceptada. No es posible que la respuesta que aceptó realmente le haya funcionado como está escrita.
Aaron Bertrand

Respuestas:

165

¿Está buscando sys.schemas ?

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

Tenga en cuenta que CREATE SCHEMAdebe ejecutarse en su propio lote (según la respuesta a continuación )

bdukes
fuente
Maldición ... en el tiempo que me tomó editar la publicación para hacerla más legible ... arreglaste mi problema. Muchas gracias!
Pulsehead
18
esto no funciona en SQL 2008 porque CREATE SCHEMA debe ser la primera declaración de un lote, consulte la publicación de vfilby para obtener una solución alternativa
sergiom
4
Puede usar 'Seleccionar 1 de sys.schemas' para mejorar el rendimiento.
vijaysylvester
4
@vijaysylvester No, esto es un mito. SQL Server optimiza la lista de columnas para que no importe lo que ponga allí. Totalmente ignorado. ¿Quieres una prueba? PutSELECT 1/0...
Aaron Bertrand
1
Actualicé
157

@bdukes tiene razón en el dinero para determinar si el esquema existe, pero la declaración anterior no funcionará en SQL Server 2005. CREATE SCHEMA <name>necesita ejecutarse en su propio lote. Una solución es ejecutar la CREATE SCHEMAdeclaración en un ejecutivo.

Esto es lo que usé en mis scripts de compilación:

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
fuente
¡Funciona de maravilla! esto incluso me permite poner mis declaraciones impresas y todo.
Tony
2

Esto es antiguo, así que me siento obligado a agregar: Para SQL SERVER 2008+ Todo esto funciona (para la parte seleccionada), luego utilícelo EXECUTE('CREATE SCHEMA <name>')para crearlo con resultados negativos.

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
fuente
IF schema_id ('MySchemaName') IS NULLfunciona bien y parece un poco más conveniente que la respuesta aceptada.
BradC
1

Solo para ser más "defensivo", la siguiente versión genera un error de conversión de tipo para tener en cuenta la posibilidad (aunque improbable) de> 1 coincidencia Schemasimilar a cómo el código de validación a menudo arroja intencionalmente excepciones porque creo que es bueno y creo que es "mejores prácticas" para tener en cuenta todos los posibles resultados devueltos, por poco probables que sean, e incluso si es solo para generar una excepción fatal porque los efectos conocidos de detener el procesamiento suelen ser mejores que los efectos en cascada desconocidos de los errores no atrapados. Debido a que es muy poco probable, no pensé que valiera la pena la molestia de una Countverificación separada + Throwo Try- Catch- Throwpara generar un error fatal más fácil de usar, pero aún así un error fatal.

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

Luego:

if @HasSchemaX = 1
begin
   ...
end -- if @HasSchemaX = 1
Tom
fuente
Supongo que es posible tener más de un esquema coincidente cuando usa una intercalación sensible a mayúsculas y minúsculas, pero su "manejo de errores" dará como resultado el siguiente error: La conversión falló al convertir el valor varchar 'ERROR' al tipo de datos int.
user247702
@Stijn: Eso es "por diseño" similar a cómo el código de validación a menudo es intencionalmente Throw Exception. Como usted ha dicho, no es " 'probable'" a suceder, por lo que en mi humilde opinión, no valía la pena en su conjunto Try- Catcho separada Countde verificación para generar un error fatal más fácil de usar, pero independientemente, yo probablemente querrá un error fatal. Creo y creo que es "la mejor práctica" tener en cuenta todos los posibles resultados devueltos, por poco probables que sean, e incluso si es solo para generar una excepción fatal porque los efectos conocidos de detener el procesamiento suelen ser mejores que los efectos en cascada desconocidos de no atrapado errores.
Tom
Todo eso suena bien, no estaba seguro de si fue intencional :) Su respuesta podría beneficiarse de alguna explicación adicional, como acaba de dar en su comentario.
user247702
@Stijn: Mi mascota fastidio es el común no tan " 'mejores prácticas'" de no comprobar si un Select, Insert, Updateo Deletesentencia ha devuelto / afectó a más o menos que el # de filas esperado por improbable. Incluso si hay (hay) Unique Indexactualmente asegurando que el # esperado (es decir, 1) de Filas sean devueltas / afectadas, eso podría cambiar (accidentalmente o (miope) "'intencionalmente'") en el futuro.
Tom
1

Si el diseño de los componentes lo permite, esto también funciona.

SI EXISTE (SELECCIONE 1 DE sys.schemas DONDE name = 'myschema') ESTABLEZCA NOEXEC ON 
Vamos
CREAR ESQUEMA myschema
VAMOS 
SET NOEXEC OFF - si se necesita algún procesamiento adicional.
VAMOS
benik9
fuente