ฉันจะสอบถามว่าสคีมาฐานข้อมูลมีอยู่ได้อย่างไร


102

ในขั้นตอนการสร้างของเราเราเรียกใช้สคริปต์อัพเดตฐานข้อมูลเมื่อเราปรับใช้โค้ดกับ 4 สภาพแวดล้อม นอกจากนี้เนื่องจากข้อความค้นหาเดียวกันจะถูกเพิ่มเข้าไปจนกว่าเราจะวางรุ่นลงในเวอร์ชันที่ใช้งานจริงจึงต้องสามารถเรียกใช้หลายครั้งบนฐานข้อมูลที่กำหนด แบบนี้:

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

ขณะนี้ฉันมีคำสั่งสร้างสคีมาในสคริปต์การปรับใช้ / การสร้าง ฉันจะสอบถามการมีอยู่ของสคีมาได้ที่ไหน


2
โปรดพิจารณาเปลี่ยนคำตอบที่ยอมรับ เป็นไปไม่ได้ที่คำตอบที่คุณยอมรับจะได้ผลจริงตามที่เขียนไว้
Aaron Bertrand

คำตอบ:


169

คุณกำลังมองหาsys.schemasหรือไม่?

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

โปรดทราบว่าCREATE SCHEMAต้องรันในชุดของตัวเอง (ตามคำตอบด้านล่าง )


ยี้ ... ในเวลาที่ฉันต้องแก้ไขโพสต์เพื่อให้อ่านง่ายขึ้น ... คุณแก้ไขปัญหาของฉันได้ ขอบคุณ mucho!
Pulsehead

18
สิ่งนี้ใช้ไม่ได้ใน SQL 2008 เนื่องจาก CREATE SCHEMA ต้องเป็นคำสั่งแรกในชุดงานโปรดดูโพสต์ vfilby สำหรับวิธีแก้ปัญหา
sergiom

4
คุณสามารถใช้ 'เลือก 1 จาก sys.schemas' เพื่อปรับปรุงประสิทธิภาพ
vijaysylvester

4
@vijaysylvester ไม่นี่คือตำนาน SQL Server เพิ่มประสิทธิภาพรายการคอลัมน์ดังนั้นจึงไม่สำคัญว่าคุณจะใส่อะไรไว้ที่นั่น ละเว้นโดยสิ้นเชิง ต้องการหลักฐาน? พุทSELECT 1/0...
Aaron Bertrand

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

ใช้งานได้เหมือนมีเสน่ห์! สิ่งนี้ทำให้ฉันสามารถพิมพ์ข้อความและทุกอย่างได้
Tony

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

1
IF schema_id ('MySchemaName') IS NULLใช้งานได้ดีและดูเหมือนจะสะดวกกว่าคำตอบที่ยอมรับเล็กน้อย
BradC

เห็นด้วย @BradC. สำหรับผู้ที่ได้รับข้อยกเว้น: IF SCHEMA_ID ('out') IS NULL EXEC ('CREATE SCHEMA [out] AUTHORIZATION [out]');
Juozas

1

เพียงเพื่อจะได้เสริม "การป้องกัน" รุ่นต่อไปนี้สร้างข้อผิดพลาดประเภทการแปลงไปยังบัญชีสำหรับความเป็นไปได้ ( แต่ไม่น่า) ของ> 1 จับคู่Schema's คล้ายกับรหัสการตรวจสอบมักจะจงใจโยนข้อยกเว้นเพราะผมเชื่อว่ามันเป็นเรื่องดีที่และผมเชื่อว่ามันเป็น "'แนวทางปฏิบัติที่ดีที่สุด'" เพื่ออธิบายผลลัพธ์ที่เป็นไปได้ทั้งหมด แต่ไม่น่าเป็นไปได้และแม้ว่าจะเป็นเพียงการสร้างข้อยกเว้นที่ร้ายแรงเนื่องจากผลกระทบที่ทราบจากการหยุดการประมวลผลมักจะดีกว่าผลการเรียงซ้อนที่ไม่ทราบสาเหตุของข้อผิดพลาดที่ไม่ติดกับดัก เพราะมันไม่น่าจะสูงผมไม่ได้คิดว่ามันคุ้มค่าปัญหาของแยกCountเช็ค + ThrowหรือTry- Catch-Throwเพื่อสร้างมิตรกับผู้ใช้ข้อผิดพลาดร้ายแรงมากขึ้น แต่ยังคงมีข้อผิดพลาดร้ายแรงกระนั้น

เอสเอส 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's เช่นเดียวกับที่คุณกล่าวว่ามันไม่ได้ "แนวโน้ม" ที่จะเกิดขึ้นดังนั้น IMHO มันก็ไม่คุ้มค่าทั้งTry- CatchหรือแยกจากกันCountตรวจสอบเพื่อสร้างข้อผิดพลาดร้ายแรงขึ้นใช้งานง่าย แต่ไม่ว่าผมจะมีแนวโน้มที่ต้องการข้อผิดพลาดร้ายแรง ฉันเชื่อและเชื่อว่านี่เป็น "แนวทางปฏิบัติที่ดีที่สุด" ในการอธิบายผลลัพธ์ที่เป็นไปได้ทั้งหมดอย่างไรก็ตามไม่น่าเป็นไปได้และแม้ว่าจะเป็นเพียงการสร้างข้อยกเว้นที่ร้ายแรงเนื่องจากผลกระทบที่ทราบจากการหยุดการประมวลผลมักจะดีกว่าเอฟเฟกต์การเรียงซ้อนที่ไม่รู้จัก ข้อผิดพลาด
ทอม

ทุกอย่างฟังดูดีฉันไม่แน่ใจว่าเจตนา :) คำตอบของคุณอาจได้รับประโยชน์จากคำอธิบายเพิ่มเติมบางอย่างเช่นที่คุณให้ไว้ในความคิดเห็นของคุณ
user247702

@Stijn: โกรธสัตว์เลี้ยงของฉันคือร่วมกันไม่ให้ "ปฏิบัติที่ดีที่สุด" ของการไม่ตรวจสอบถ้าSelect, Insert, UpdateหรือDeleteคำชี้แจงกลับ / ผลกระทบมากขึ้นหรือน้อยกว่า # แถว แต่ไม่น่าคาดว่า แม้ว่าจะมี (are) Unique Indexอยู่ในขณะนี้ที่มั่นใจว่า # (คือ 1) ของแถวที่คาดว่าจะถูกส่งคืน / ได้รับผลกระทบ แต่อาจมีการเปลี่ยนแปลง (โดยบังเอิญหรือ (สายตาสั้น) "'โดยเจตนา'") ในอนาคต
ทอม

1

หากเค้าโครงของส่วนประกอบอนุญาตสิ่งนี้ก็ใช้ได้เช่นกัน

หากมีอยู่ (เลือก 1 จาก sys.schemas WHERE name = 'myschema') ตั้งค่า NOEXEC 
ไป
สร้าง SCHEMA myschema
ไป 
SET NOEXEC OFF - หากจำเป็นต้องมีการประมวลผลเพิ่มเติม
ไป
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.