TSQL - BEGIN .. END bloğunun içinde GO nasıl kullanılır?


97

Değişiklikleri birden çok geliştirme veritabanından hazırlama / üretime otomatik olarak geçirmek için bir komut dosyası oluşturuyorum. Temel olarak, bir dizi değişiklik betiğini alır ve bunları tek bir betikte birleştirerek her bir komut dosyasını bir IF whatever BEGIN ... ENDifadeye sarar.

Ancak, bazı komut dosyaları GO, örneğin SQL ayrıştırıcısının oluşturulduktan sonra yeni bir sütun hakkında bilgi sahibi olması için bir ifade gerektirir .

ALTER TABLE dbo.EMPLOYEE 
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO -- Necessary, or next line will generate "Unknown column:  EMP_IS_ADMIN"
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever

Ancak, bunu bir IFbloğa sardığımda:

IF whatever
BEGIN
    ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
    GO
    UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
END

Başarısız oluyor çünkü BEGINeşleşme olmadan bir gönderiyorum END. Ancak, kaldırırsam, GObilinmeyen bir sütun hakkında tekrar şikayet ediyor.

Aynı sütunu tek bir IFblokta oluşturmanın ve güncellemenin herhangi bir yolu var mı ?



2
@gbn: Evet, bunun neden olduğunu anlıyorum (ikinci paragrafa bakın) ; ancak bunun üzerinden nasıl geçeceğime dair hiçbir fikrim yok - gerçekten her sorguyu bir dizi dizgiye dönüştürmem gerekiyor mu?
BlueRaja - Danny Pflughoeft

@BlueRaja: Sorun nedir? İşe yararsa, günün sonunda önemli olan budur. Sağlanan çözümle ilgili meşru bir iş sorunu varsa, lütfen bunu belirtin. Her sorguyu bir grup dizgiye dönüştürmek konusunda özellikle rahatsız edici bir şey var mı?
mellamokb

2
@mellamokb: Evet, bir sorun var; GO kelimesi başka herhangi bir bağlamda kullanılırsa (yorum veya dize gibi), komut dosyası çalışmayacaktır. Ayrıca, herhangi bir terslik olması durumunda hata mesajlarındaki yararlı satır numaralarını kaybediyoruz. Bunu işlemlerle yapmanın bir yolu yok mu? Veya dene / yakala?
BlueRaja - Danny Pflughoeft

@BlueRaja: 1) Tek GObaşına bir satırda olması gerektiğine inanıyorum , bu nedenle yalnızca bu vakayı arayabilirsiniz, kelimenin her örneğini değil GO. 2) Hangi ifadelerin başarıyla tamamlandığını her zaman kaydedebilirsiniz. Ya da hepsini bir dene / yakala içine kaydırabilir ve kendi satır numaralarınızı, takip ettiğiniz @lineNo gibi bazı değişkenler kullanarak kullanabilir ve hata durumunda raporlayabilirsiniz. Bunları otomatik olarak oluşturduğunuz için, böyle değişiklikler yapmak çocuk oyuncağı olmalı. Tüm endişelerinize çözüm bulunabileceğini düşündüğümde, bu rotayı keşfetmek istemiyormuşsunuz gibi geliyor.
mellamokb

Yanıtlar:


47

Aynı sorunu yaşadım ve sonunda SET NOEXEC kullanarak çözmeyi başardım .

IF not whatever
BEGIN
    SET NOEXEC ON; 
END

ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever

SET NOEXEC OFF; 

2
Bu harika bir çözüm!
Bazinga

+1! Bu, İfadelerin içindeki bazı çağrılarla diğer SS Komut Dosyalarını (yani alt dağıtım komut dosyalarını) çağıran ( komut yoluyla) bir SS Modu Komut Dosyasında (yani bir ana dağıtım komut dosyasında) kullanım için YALNIZCA pratik Cevaptır. Oded'in, mellamokb'un ve Andy Joiner'in tüm bu İfadeleri Çağrılara / - ' lere ekleyen Cevapları başlangıç ​​değildir. Ayrıca, - yöntemi bir İfade varsa çalışmaz (örneğin, ondan önce açık bir açıklama gerektirir ). Ama adamım, "Kutsal çifte negatifler, Batman!" ;)SQLCMD:rifexecbeginendbeginendcreatego
Tom

Okunabilirlik için (örneğin, çift negatiflerin üstesinden gelmeye yardımcı olmak ve sanal bir if bloğu simüle ettiğini daha açık hale getirmek için ), bloğun önüne bir -- If whateverYorum ekler, bloğu girintiler ve bloğa bir Yorum koyardım --end If whatever.
Tom

Pastırmamı kurtardın! Birleştirme ifadeleri çalıştırıyordum ve o aptal
GO'lar

Hm, set noexec on çalıştırıldıktan sonra güncellemede bir şekilde hata alıyorum? (güncellenecek sütun adının geçersiz olması hatası) Sorgu düzenleyicide MSSQL 2014 üzerinde çalışıyor. Koşul yanlış olursa iyi çalışır (bu nedenle noexec devre dışı kalır)
Jerry

44

GO SQL değildir - sadece bazı MS SQL araçlarında kullanılan bir toplu ayırıcıdır.

Bunu kullanmazsanız, ifadelerin farklı gruplar halinde veya nüfus için dinamik SQL kullanarak ayrı ayrı yürütüldüğünden emin olmanız gerekir (teşekkürler @gbn):

IF whatever
BEGIN
    ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL;

    EXEC ('UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever')
END

8
Evet bunu anladım. Bu soruya cevap vermiyor - Aynı IFblokta bir sütun oluşturmam ve güncellemem gerekiyor .
BlueRaja - Danny Pflughoeft

@Oded: ;Burada yardım eder misiniz ? - Cevabınızı az önce düzenlediniz: o)
Neil Knight

@Neil - bu benim düşüncem, evet.
Oded

;da çalışmıyor - ayrıştırıcı hala bana "Geçersiz sütun adı 'EMP_IS_ADMIN' veriyor."
BlueRaja - Danny Pflughoeft

Toplu iş derlendiğinde, EMP_IS_ADMIN mevcut değildir. stackoverflow.com/questions/4855537/…
gbn

17

Aşağıdaki örnekte gösterildiği gibi, sp_executesqlher bir GOifadenin içeriğini , yürütülecek ayrı bir dizeye bölmeyi deneyebilirsiniz . Ayrıca, bir istisna meydana geldiğinde kolay hata ayıklama için hangi ifadenin yürütüldüğünü izlemek için bir @statementNo değişkeni vardır. Satır numaraları, hataya neden olan ilgili ifade numarasının başlangıcına göre olacaktır.

BEGIN TRAN

DECLARE @statementNo INT
BEGIN TRY
    IF 1=1
    BEGIN
        SET @statementNo = 1
        EXEC sp_executesql
            N'  ALTER TABLE dbo.EMPLOYEE
                    ADD COLUMN EMP_IS_ADMIN BIT NOT NULL'

        SET @statementNo = 2
        EXEC sp_executesql
            N'  UPDATE dbo.EMPLOYEE
                    SET EMP_IS_ADMIN = 1'

        SET @statementNo = 3
        EXEC sp_executesql
            N'  UPDATE dbo.EMPLOYEE
                    SET EMP_IS_ADMIN = 1x'
    END
END TRY
BEGIN CATCH
    PRINT 'Error occurred on line ' + cast(ERROR_LINE() as varchar(10)) 
       + ' of ' + 'statement # ' + cast(@statementNo as varchar(10)) 
       + ': ' + ERROR_MESSAGE()
    -- error occurred, so rollback the transaction
    ROLLBACK
END CATCH
-- if we were successful, we should still have a transaction, so commit it
IF @@TRANCOUNT > 0
    COMMIT

Ayrıca, yukarıdaki örnekte gösterildiği gibi, çok satırlı ifadeleri tek tırnak ( ') içine alarak kolayca yürütebilirsiniz . ''Komut dosyalarını oluştururken dize içinde bulunan tek tırnak işaretlerinden çift tek tırnak ( ) ile kaçmayı unutmayın .


Bunun birden çok satıra bölünmüş komutlar için işe yarayacağını düşünmeyin, değil mi?
BlueRaja - Danny Pflughoeft

@BlueRaja: Nasıl çalışacağını göstermek için örneği güncelledim. Bu dizeler, içinde bulunan herhangi bir tek tırnak (') çift tek tırnak (' ') kullanılarak
atlandığı sürece çok satırlı olabilir

1
@mellamokb: Kesinlikle, sadece UPDATE için sp_executesql gerekir ... stackoverflow.com/questions/4855537/…
gbn

1
@gbn: Doğru. Ancak bunu 100'lerce ifade için otomatikleştirecekseniz, ne zaman ve nerede ihtiyacınız olduğuna karar vermek yerine tüm ifadelere körü körüne uygulamak daha kolay olacaktır.
mellamokb

@gbn @mellamokb: Gibi ifadeleri kastettim SELECT * <newline> FROM whatever. Her satırı kendi EXEC ifadesiyle yürütürsem, bu kesilir. Yoksa her GOifadede kırılmamı mı öneriyorsun ?
BlueRaja - Danny Pflughoeft

9

Sonunda GOkendi satırındaki her örneğini şu şekilde değiştirerek çalıştırdım:

END
GO

---Automatic replacement of GO keyword, need to recheck IF conditional:
IF whatever
BEGIN

Bu, her ifade grubunu bir dizeye sarmak yerine büyük ölçüde tercih edilir, ancak yine de ideal olmaktan uzaktır . Herhangi biri daha iyi bir çözüm bulursa, bunu yayınlayın ve onun yerine kabul edeceğim.


6
İlk koşul "eğer bu sütun yoksa" ise, bloktaki ilk ifade "bu sütunu ekle" ise, koşulun ikinci kontrolü sütunu bulacak ve ikinci ifadeyi çalıştırmayacaktır,
Damien_The_Unbeliever

@Damien: Doğru; neyse ki, bu benim durumumda asla olmayacak (koşullu her zaman belirli bir tablodaki belirli bir değeri kontrol etmektir ve her zaman IFbloğun son ifadesi olarak eklenir ). Bunu SQL'de yapmanın iyi bir yolu yokmuş gibi görünüyor.
BlueRaja - Dany Pflughoeft

Mina Jacob'ın set noexecYanıtı, diğer SS Komut Dosyalarını (yani alt dağıtım komut dosyalarını) İfadeler içindeki bazı çağrılarla çağıran ( komut yoluyla) bir SS Modu Komut Dosyasında (yani bir ana dağıtım komut dosyasında) kullanılmak üzere şimdiye kadar YALNIZCA pratik Cevaptır. Oded'in, mellamokb'un ve Andy Joiner'in tüm bu İfadeleri Çağrılara / - ' lere ekleyen Cevapları başlangıç ​​değildir. Ayrıca, - yöntemi bir İfade varsa çalışmaz (örneğin, ondan önce açık bir açıklama gerektirir ). SQLCMD:rifexecbeginendbeginendcreatego
Tom

8

İfadeleri arasında GO yerine BEGIN ve END'e ekleyebilirsiniz.

IF COL_LENGTH('Employees','EMP_IS_ADMIN') IS NULL --Column does not exist
BEGIN
    BEGIN
        ALTER TABLE dbo.Employees ADD EMP_IS_ADMIN BIT
    END

    BEGIN
        UPDATE EMPLOYEES SET EMP_IS_ADMIN = 0
    END
END

(Northwind veritabanında test edildi)

Düzenleme: (Muhtemelen SQL2012'de test edilmiştir)


1
Lütfen -1 için bir sebep
Andy Joiner

1
Neden olumsuz oy verildiğini bilmiyorum ... benim için bir cazibe gibi çalışıyor.
Thorarin

10
SQL Server 2008 R2 kullandığımda, bu benim için işe yaramıyor gibi görünüyor, yine de 'Geçersiz sütun adı' EMP_IS_ADMIN 'hatası alıyorum.' UPDATE satırında.
MerickOWA

BEGIN-END toplu işlemi, SQL Server 2016 kullanarak benim için çalıştı. IMO bu en temiz sözdizimidir.
Uber Schnoz

Mina Jacob'ın set noexecYanıtı, diğer SS Komut Dosyalarını (yani alt dağıtım komut dosyalarını) İfadeler içindeki bazı çağrılarla çağıran ( komut yoluyla) bir SS Modu Komut Dosyasında (yani bir ana dağıtım komut dosyasında) kullanılmak üzere şimdiye kadar YALNIZCA pratik Cevaptır. Oded'in, mellamokb'un ve Andy Joiner'in tüm bu İfadeleri Çağrılara / - ' lere ekleyen Cevapları başlangıç ​​değildir. Ayrıca, - yöntemi bir İfade varsa çalışmaz (örneğin, ondan önce açık bir açıklama gerektirir ). SQLCMD:rifexecbeginendbeginendcreatego
Tom

1

Bu çözümü deneyebilirsiniz:

if exists(
SELECT...
)
BEGIN
PRINT 'NOT RUN'
RETURN
END

--if upper code not true

ALTER...
GO
UPDATE...
GO

1
Birbiri ardına birkaç if-else bloğunuz varsa pek kullanışlı değil, değil mi?
Jerry

0

Bunun RAISERRORiçin geçmişte kullandım

IF NOT whatever BEGIN
    RAISERROR('YOU''RE ALL SET, and sorry for the error!', 20, -1) WITH LOG
END

ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever

-1

Kodu atlamak için a GOTOve LABELifadeleri ekleyebilir, böylece GOanahtar kelimeleri olduğu gibi bırakabilirsiniz .


6
Görünüşe göre LABEL'lere SQL'e gönderilen toplu iş içinde olmadıklarından GO deyimleri arasında başvurulamaz
berkeleybross
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.