Bir seferde bir değişkeni sürdürmenin bir yolu var mı?


84

Bir seferde bir değişkeni sürdürmenin bir yolu var mı?

Declare @bob as varchar(50);
Set @bob = 'SweetDB'; 
GO
USE @bob  --- see note below
GO
INSERT INTO @bob.[dbo].[ProjectVersion] ([DB_Name], [Script]) VALUES (@bob,'1.2')

'USE @bob' satırı için bu SO sorusuna bakın .


Tablo adını neden DB adıyla nitelendirmeniz gerekiyor? Sanırım bundan önce de benzer bir soru sorulmuştu.
shahkalpesh

Ve tablo adlarını böyle bir değişkendeki veritabanı adıyla nitelendirmenin bir yolu yoktur. USE ifadesiyle bir değişken kullanmakla ilgili önceki sorusuyla, her şeyi dinamik SQL'de, masaya sürükleyen tüm acılarla yapması gerekeceğini tahmin ediyorum.
Lasse V. Karlsen

Gerçek betik 4 farklı veritabanını bütünleştirir. DbName1, dbName2, dbName3 ve dbName4'ü bulma ve değiştirme talimatlarını yorumladım. Sadece müşterinin dört değişken ayarlamasının daha az hataya meyilli olacağını düşündüm.
NitroxDM

Soru başlığı gerçekten önemli bir sorudur, ancak örnek kod korkunçtur. Kabul edilen yanıtın gösterdiği gibi, örneğinizde 'gitmeye' ihtiyacınız yoktu. Sonuç, kabul edilen cevabın başlığınızdaki soruya cevap vermemesidir.
Greg Woods

Yanıtlar:


31

goKomut ayrı gruplar halinde kodunu bölmek için kullanılır. Eğer tam olarak yapmak istediğiniz şey buysa, onu kullanmalısınız, ancak bu, partilerin aslında ayrı olduğu ve aralarında değişkenleri paylaşamayacağınız anlamına gelir.

Sizin durumunuzda çözüm basit; sadece goifadeleri kaldırabilirsiniz, bu kodda bunlara gerek yoktur.

Yan not: Bir useifadede bir değişken kullanamazsınız , bir veritabanının adı olmalıdır.


1
Bazı SQL İfadeleri bir bloktaki ilk ifade olmalıdır (GO ifadeleri arasındaki bölge). Örneğin: CREATE PROCEDURE veya CREATE FUNCTION, diğer tüm ifadelerden önce - ya kodun üstünde ya da GO ifadesinin hemen ardından - gerçekleşmelidir (not: beyaz boşluk ve yorumlara bu ifadelerden önce izin verilir). Bu tür ifadelerin diğer mantıktan sonra gerçekleşmesi gereken komut dosyalarını çalıştırırken, GO ifadeleri gereklidir. Ancak çoğu durumda GO ifadelerinin kaldırılabileceğini kabul etmeliyim.
Zarepheth

@Zarepheth: İyi nokta. Bu özel kodda buna gerek yoktur, ancak bazı durumlarda gerekli olabileceğini bilmek yararlıdır.
Guffa

1
Neden olumsuz oy? Yanlış olduğunu düşündüğünüz şeyin ne olduğunu açıklamazsanız, cevabı iyileştiremez.
Guffa

2
@jwize: Hayır, onları ayırmanıza gerek yok, bu aynı blokta yapılabilir.
Guffa

1
@Ben: goKomut, kodu ayrı gruplara bölmek için kullanılır. Eğer yapmak istediğiniz buysa, onu kullanmalısınız, ancak bu, partilerin aslında ayrı olduğu ve aralarında değişkenleri paylaşamayacağınız anlamına gelir.
Guffa

131

Geçici bir tablo kullanın:

CREATE TABLE #variables
    (
    VarName VARCHAR(20) PRIMARY KEY,
    Value VARCHAR(255)
    )
GO

Insert into #variables Select 'Bob', 'SweetDB'
GO

Select Value From #variables Where VarName = 'Bob'
GO

DROP TABLE #variables
go

13
harika cevap ... aslında bir çalışma yapmaktansa SORULAN soruyu CEVAPLADIN.
Cos Callis

1
Bu doğru cevap. Güzel çözüm. Ayrıca, çok sayıda değişken kullanırsanız, bunların hepsi tek bir kolay erişilebilir tablodadır, SP'de beyannamelerinizi aramak için yukarı ve aşağı kaydırma gerekmez.
ColinMac

15

Bu sorunun cevabını GO ile Global Değişkenler tercih ediyorum

Bu, başlangıçta yapmak istediğiniz şeyi yapabilmenin ek faydasına da sahiptir.

Uyarı, SQLCMD modunu açmanız (Sorgu-> SQLCMD altında) veya tüm sorgu pencereleri için varsayılan olarak açmanız gerektiğidir (Araçlar-> Seçenekler sonra Sorgu Sonuçları-> Varsayılan olarak, SQLCMD modunda yeni sorgular açın)

O zaman aşağıdaki kod türünü kullanabilirsiniz (aynı cevap Oscar E. Fraxedas Tormo tarafından tamamen koparılmıştır )

--Declare the variable
:setvar MYDATABASE master
--Use the variable
USE $(MYDATABASE);
SELECT * FROM [dbo].[refresh_indexes]
GO
--Use again after a GO
SELECT * from $(MYDATABASE).[dbo].[refresh_indexes];
GO

SQLCMD modunda sorgu çıktısını başka bir dosyaya (: out filename) yeniden yönlendiriyordum ve çıktıyı dosyaya boşaltmak için bir GO yürütmeniz gerekiyor, yani bu: setvar sözdizimi bu durumda normal değişkenleri değiştirmek için gereklidir çünkü siz ' işleri gruplara ayırmaya zorlanıyor.
Anssssss

Harika! Bu aslında gerçek doğru cevap olarak işaretlenmelidir!
SQL Police

4

SQL Server kullanıyorsanız, aşağıdaki gibi tüm komut dosyaları için genel değişkenler ayarlayabilirsiniz:

:setvar sourceDB "lalalallalal"

ve daha sonra komut dosyasında şu şekilde kullanın:

$(sourceDB)

Sunucu Yönetimi Çalışmasında SQLCMD modunun açık olduğundan emin olun, bunu üst menü aracılığıyla yapabilirsiniz Sorgu'ya tıklayın ve SQLCMD Modunu açın.

Konuyla ilgili daha fazla bilgiyi burada bulabilirsiniz: MS Belgeleri


1

Bunun yardımcı olup olmadığından emin değilim

declare @s varchar(50)
set @s='Northwind'

declare @t nvarchar(100)
set @t = 'select * from ' + @s + '.[dbo].[Customers]'

execute sp_executesql @t

1

Geçici tablolar GO ifadeleri üzerinde tutulur, bu nedenle ...

SELECT 'value1' as variable1, 'mydatabasename' as DbName INTO #TMP

-- get a variable from the temp table
DECLARE @dbName VARCHAR(10) = (select top 1 #TMP.DbName from #TMP)
EXEC ('USE ' + @dbName)
GO

-- get another variable from the temp table
DECLARE @value1 VARCHAR(10) = (select top 1 #TMP.variable1 from #TMP)

DROP TABLE #TMP

Hoş değil ama işe yarıyor


1

Geçici bir tabloya kaydeden / yükleyen kendi saklı yordamlarınızı oluşturun.

MyVariableSave   -- Saves variable to temporary table. 
MyVariableLoad   -- Loads variable from temporary table.

O zaman bunu kullanabilirsiniz:

print('Test stored procedures for load/save of variables across GO statements:')

declare @MyVariable int = 42
exec dbo.MyVariableSave @Name = 'test', @Value=@MyVariable
print('  - Set @MyVariable = ' + CAST(@MyVariable AS VARCHAR(100)))

print('  - GO statement resets all variables')
GO -- This resets all variables including @MyVariable

declare @MyVariable int
exec dbo.MyVariableLoad 'test', @MyVariable output
print('  - Get @MyVariable = ' + CAST(@MyVariable AS VARCHAR(100)))

Çıktı:

Test stored procedures for load/save of variables across GO statements:
  - Set @MyVariable = 42
  - GO statement resets all variables
  - Get @MyVariable = 42

Bunları da kullanabilirsiniz:

exec dbo.MyVariableList       -- Lists all variables in the temporary table.
exec dbo.MyVariableDeleteAll  -- Deletes all variables in the temporary table.

Çıktı exec dbo.MyVariableList:

Name    Value
test    42

Bir tablodaki tüm değişkenleri listelemenin aslında oldukça yararlı olduğu ortaya çıktı. Dolayısıyla, bir değişkeni daha sonra yüklemeseniz bile, her şeyi tek bir yerde görmek hata ayıklama amaçları için harikadır.

Bu, ##ön ekli geçici bir tablo kullanır , bu nedenle bir GO ifadesinden kurtulmak için yeterlidir. Tek bir komut dosyası içinde kullanılması amaçlanmıştır.

Ve saklanan prosedürler:

-- Stored procedure to save a variable to a temp table.
CREATE OR ALTER PROCEDURE MyVariableSave 
    @Name varchar(255),
    @Value varchar(MAX)
WITH EXECUTE AS CALLER
AS  
BEGIN
    SET NOCOUNT ON
    IF NOT EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        DROP TABLE IF EXISTS ##VariableLoadSave
        CREATE TABLE ##VariableLoadSave
        (
            Name varchar(255),
            Value varchar(MAX)
        )
    END
    UPDATE ##VariableLoadSave SET Value=@Value WHERE Name=@Name
    IF @@ROWCOUNT = 0
        INSERT INTO ##VariableLoadSave SELECT @Name, @Value
END
GO
-- Stored procedure to load a variable from a temp table.
CREATE OR ALTER PROCEDURE MyVariableLoad 
    @Name varchar(255),
    @Value varchar(MAX) OUT
WITH EXECUTE AS CALLER
AS  
BEGIN
    IF EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        IF NOT EXISTS(SELECT TOP 1 * FROM ##VariableLoadSave WHERE Name=@Name)
        BEGIN
            declare @ErrorMessage1 as varchar(200) = 'Error: cannot find saved variable to load: ' + @Name
            raiserror(@ErrorMessage1, 20, -1) with log
        END

        SELECT @Value=CAST(Value AS varchar(MAX)) FROM ##VariableLoadSave
        WHERE Name=@Name
    END
    ELSE
    BEGIN
        declare @ErrorMessage2 as varchar(200) = 'Error: cannot find saved variable to load: ' + @Name
        raiserror(@ErrorMessage2, 20, -1) with log
    END
END
GO
-- Stored procedure to list all saved variables.
CREATE OR ALTER PROCEDURE MyVariableList
WITH EXECUTE AS CALLER
AS  
BEGIN
    IF EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        SELECT * FROM ##VariableLoadSave
        ORDER BY Name
    END
END
GO
-- Stored procedure to delete all saved variables.
CREATE OR ALTER PROCEDURE MyVariableDeleteAll
WITH EXECUTE AS CALLER
AS  
BEGIN
    DROP TABLE IF EXISTS ##VariableLoadSave
    CREATE TABLE ##VariableLoadSave
    (
        Name varchar(255),
        Value varchar(MAX)
    )
END

0

Eğer sadece ikili bir evet / hayır'a ihtiyacınız varsa (bir sütun varsa gibi) SET NOEXEC ON, ifadelerin yürütülmesini devre dışı bırakmak için kullanabilirsiniz . SET NOEXEC ONGO genelinde çalışır (gruplar arasında). Ama üzerinde EXEC sırtını dönmeye hatırlamak ile SET NOEXEC OFFkomut sonunda.

IF COL_LENGTH('StuffTable', 'EnableGA') IS NOT NULL
    SET NOEXEC ON -- script will not do anything when column already exists

ALTER TABLE dbo.StuffTable ADD EnableGA BIT NOT NULL CONSTRAINT DF_StuffTable_EnableGA DEFAULT(0)
ALTER TABLE dbo.StuffTable SET (LOCK_ESCALATION = TABLE)
GO
UPDATE dbo.StuffTable SET EnableGA = 1 WHERE StuffUrl IS NOT NULL
GO
SET NOEXEC OFF

Bu, ifadeleri derler, ancak onları çalıştırmaz. Dolayısıyla, mevcut olmayan şemaya başvurursanız, yine de "derleme hataları" alırsınız. Bu nedenle, 2. çalıştırma (yaptığım şey) komut dosyasını "kapatmak" için çalışır, ancak 1. çalıştırmada komut dosyasının bölümlerini kapatmak için çalışmaz, çünkü yine de sütunlara veya tablolara referans verirseniz derleme hataları alacaksınız. Henüz yok.


0

NOEXEC'i aşağıdaki adımları takip ederek kullanabilirsiniz:

Tablo oluştur

#temp_procedure_version(procedure_version varchar(5),pointer varchar(20))

bir geçici tabloya prosedür sürümlerini ve sürüme işaretçi ekleme #temp_procedure_version

--örnek prosedür_version işaretçisi

temp_procedure_versiondeğerlere ekle (1.0, "ilk sürüm")

temp_procedure_versiondeğerlere ekle (2.0, "son sürüm")

daha sonra prosedür sürümünü geri alın, where koşulunu aşağıdaki ifadede olduğu gibi kullanabilirsiniz

Seç @ProcedureVersion=ProcedureVersiongelen #temp_procedure_versionnerede pointer='first version'

IF (@ProcedureVersion='1.0')
    BEGIN
    SET NOEXEC OFF  --code execution on 
    END
ELSE
    BEGIN 
    SET NOEXEC ON  --code execution off
    END 

- buraya prosedür versiyon 1.0 ekleyin

İşlem versiyon 1.0'ı aşağıdaki gibi oluşturun ...

SET NOEXEC OFF -- execution is ON

Seç @ProcedureVersion=ProcedureVersiongelen #temp_procedure_versionnerede işaretçi = 'son hali'

IF (@ProcedureVersion='2.0')
    BEGIN
    SET NOEXEC OFF  --code execution on 
    END
ELSE
    BEGIN 
    SET NOEXEC ON  --code execution off
    END 

Prosedür versiyon 2.0'ı şu şekilde oluşturun ...

SET NOEXEC OFF -- execution is ON

- geçici tabloya bırakın

Tabloyu bırak #temp_procedure_version

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.