如何查询数据库架构是否存在


98

作为构建过程的一部分,我们在将代码部署到4个不同环境中时运行数据库更新脚本。此外,由于相同的查询将添加到,直到我们放下一个释放到生产它具有能够给定的数据库上运行多次。像这样:

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

目前,我在Deployment / Build脚本中有一个create schema语句。在哪里查询模式的存在?


2
请考虑更改接受的答案。您接受的答案不可能如您所写的那样实际为您服务。
亚伦·贝特朗

Answers:


165

您在寻找sys.schemas吗?

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

请注意,CREATE SCHEMA必须以自己的批次运行(按照下面的答案


该死...花了我时间编辑帖子以使其更具可读性...您解决了我的问题。非常感谢!
08年

18
这在SQL 2008中不起作用,因为CREATE SCHEMA需要成为批处理中的第一条语句,有关解决方法,请参见vfilby帖子
sergiom 2010年

4
您可以使用“从sys.schemas中选择1”来提高性能。
vijaysylvester,2012年

4
@vijaysylvester不,这是一个神话。SQL Server会优化列列表,因此您放置在此处的列表无关紧要。完全忽略了。要证明吗?放置SELECT 1/0...
亚伦·贝特朗2014年

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

奇迹般有效!这甚至可以让我发表我的打印报表和所有内容。
托尼

2

这太旧了,因此我不得不添加:对于SQL SERVER 2008+,所有这些都起作用(对于select部件),然后用于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检查+ ThrowTry- 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检查以生成一个更加用户友好的致命错误,但是无论如何,我都可能想要一个致命错误。我相信并且我相信“最佳实践”是要考虑所有可能的返回结果,但是这种可能性很小,即使只是产生致命的异常,因为停止处理的已知效果通常比未捕获的级联效果更好。错误。
汤姆(Tom)

一切听起来不错,我不确定这是否是故意的:)您的回答可以从其他解释中受益,例如您刚才的评论。
user247702

@Stijn:我的忌讳是常见的不那么“‘最佳实践’”如果不检查的SelectInsertUpdateDelete语句返回/受影响的更多小于行但不太可能的预期#。即使Unique Index当前有“ /”确保预期的行数(即1)要返回/受影响,将来也可能会发生(偶然或(短视)“故意””更改)。
汤姆,

1

如果组件的布局允许,这也可以。

如果存在(从sys.schemas中选择1,名称='myschema')设置NOEXEC ON 
走
创建模式EMA
走 
SET NOEXEC OFF-如果需要进一步处理。
走
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.