Bagaimana cara menanyakan jika skema database ada

98

Sebagai bagian dari proses pembangunan kami, kami menjalankan skrip pembaruan basis data saat kami menerapkan kode ke 4 lingkungan berbeda. Selanjutnya, karena permintaan yang sama akan ditambahkan ke sampai kita menjatuhkan sebuah rilis ke dalam produksi itu memiliki untuk dapat menjalankan beberapa kali pada database yang diberikan. Seperti ini:

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

Saat ini saya memiliki membuat pernyataan skema dalam skrip penerapan / pembuatan. Di mana saya menanyakan keberadaan skema?

Pulsehead
sumber
2
Mohon pertimbangkan untuk mengubah jawaban yang diterima. Tidak mungkin jawaban yang Anda terima benar-benar sesuai untuk Anda seperti yang tertulis.
Aaron Bertrand

Jawaban:

165

Apakah Anda mencari sys.schemas ?

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

Perhatikan bahwa CREATE SCHEMAharus dijalankan dalam batch-nya sendiri (sesuai jawaban di bawah )

bdukes
sumber
Sial ... dalam waktu yang saya perlukan untuk mengedit postingan agar lebih mudah dibaca ... Anda telah memperbaiki masalah saya. Terima kasih banyak!
Pulsehead
18
ini tidak berfungsi di SQL 2008 karena CREATE SCHEMA perlu menjadi pernyataan pertama dalam sebuah batch, lihat posting vfilby untuk solusinya
sergiom
4
Anda dapat menggunakan 'Pilih 1 dari sys.schemas' untuk meningkatkan kinerja.
vijaysylvester
4
@vijaysylvester Tidak, ini adalah mitos. SQL Server mengoptimalkan daftar kolom sehingga tidak masalah apa yang Anda taruh di sana. Benar-benar diabaikan. Mau bukti? PutSELECT 1/0...
Aaron Bertrand
1
Saya telah memperbarui jawaban ini agar tidak salah (yaitu menggunakan skrip dari bawah stackoverflow.com/a/521271/2688 )
bdukes
157

@bdukes tepat untuk menentukan apakah skema tersebut ada, tetapi pernyataan di atas tidak akan berfungsi di SQL Server 2005. CREATE SCHEMA <name>perlu dijalankan dalam kelompoknya sendiri. Solusinya adalah dengan mengeksekusi CREATE SCHEMApernyataan dalam sebuah exec.

Inilah yang saya gunakan dalam skrip build saya:

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.dll
sumber
bekerja seperti pesona! ini bahkan memungkinkan saya meletakkan pernyataan cetak saya dan segalanya.
Tony
2

Ini sudah tua jadi saya merasa harus menambahkan: Untuk SQL SERVER 2008+ Ini semua berfungsi (untuk bagian yang dipilih), kemudian gunakan EXECUTE('CREATE SCHEMA <name>')untuk benar-benar membuatnya pada hasil negatif.

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
sumber
IF schema_id ('MySchemaName') IS NULLberfungsi dengan baik, dan tampaknya sedikit lebih nyaman daripada jawaban yang diterima.
BradC
1

Hanya untuk menjadi ekstra "defensif", versi berikut menghasilkan kesalahan konversi Jenis untuk memperhitungkan kemungkinan (namun tidak mungkin)> 1 pencocokan Schemamirip dengan bagaimana kode validasi sering kali sengaja Lempar Pengecualian karena saya yakin itu baik untuk dan saya percaya itu "'Praktik terbaik'" untuk memperhitungkan semua kemungkinan hasil pengembalian namun tidak mungkin dan bahkan jika itu hanya untuk menghasilkan pengecualian fatal karena efek penghentian pemrosesan yang diketahui biasanya lebih baik daripada efek berjenjang yang tidak diketahui dari kesalahan yang tidak terperangkap. Karena sangat tidak mungkin, menurut saya tidak ada gunanya melakukan Countpemeriksaan terpisah + Throwatau Try- Catch- Throwuntuk menghasilkan kesalahan fatal yang lebih ramah pengguna tetapi tetap saja kesalahan 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

Kemudian:

if @HasSchemaX = 1
begin
   ...
end -- if @HasSchemaX = 1
Tom
sumber
Saya kira itu mungkin untuk memiliki lebih dari satu skema yang cocok ketika Anda menggunakan pemeriksaan case sensitive, tetapi "penanganan kesalahan" Anda akan menghasilkan kesalahan berikut: Konversi gagal saat mengubah nilai varchar 'ERROR' menjadi tipe data int.
pengguna247702
@Stijn: Itu "By Design" mirip dengan bagaimana kode validasi sering kali sengaja dibuat Throw Exception. Seperti yang Anda katakan, itu tidak "'mungkin'" terjadi, jadi IMHO, itu tidak layak secara keseluruhan Try- Catchatau Countpemeriksaan terpisah untuk menghasilkan kesalahan fatal yang lebih ramah pengguna, tetapi terlepas dari itu, saya kemungkinan besar menginginkan kesalahan fatal. Saya percaya dan saya percaya itu "'praktik terbaik'" untuk memperhitungkan semua kemungkinan hasil pengembalian namun tidak mungkin dan bahkan jika itu hanya untuk menghasilkan pengecualian fatal karena efek yang diketahui dari menghentikan pemrosesan biasanya lebih baik daripada efek berjenjang yang tidak diketahui dari tidak terperangkap kesalahan.
Tom
Kedengarannya baik-baik saja, saya tidak yakin apakah itu disengaja :) Jawaban Anda bisa mendapat manfaat dari beberapa penjelasan tambahan, seperti yang baru saja Anda berikan dalam komentar Anda.
pengguna247702
@Stijn: pet mengesalkan saya adalah umum tidak begitu " 'praktek terbaik'" dengan tidak memeriksa jika Select, Insert, Updateatau DeletePernyataan kembali / mempengaruhi lebih atau kurang dari yang diharapkan # dari Rows namun tidak mungkin. Meskipun saat ini ada (ada) yang Unique Indexmemastikan # (yaitu 1) dari Baris yang diharapkan dikembalikan / terpengaruh, hal itu dapat berubah (secara tidak sengaja atau (secara tidak sengaja) "'sengaja'") di masa mendatang.
Tom
1

Jika tata letak komponen memungkinkan, ini juga berfungsi.

JIKA ADA (PILIH 1 DARI sys.schemas WHERE name = 'myschema') ATUR NOEXEC ON 
Pergilah
BUAT SKEMA myschema
PERGILAH 
ATUR NOEXEC OFF - jika diperlukan pemrosesan lebih lanjut.
PERGILAH
benik9
sumber