Чи є спосіб зберегти змінну протягом ходу?


82

Чи є спосіб зберегти змінну протягом ходу?

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')

Див. Це запитання SO для рядка 'USE @bob'.


Чому вам потрібно кваліфікувати ім'я таблиці з іменем БД? Я думаю, подібне запитання було задане до цього.
shahkalpesh

І немає можливості кваліфікувати імена таблиць за допомогою імені бази даних у такій змінній. З його попереднім запитанням про використання змінної з оператором USE, я припускаю, що йому потрібно буде робити все в динамічному SQL, з усіма болями, які тягнуть до таблиці.
Лассе В. Карлсен, 02

Фактичний сценарій інтегрує 4 різні бази даних. Я прокоментував інструкції щодо пошуку та заміни dbName1, dbName2, dbName3 та dbName4. Я просто думав, що для клієнта було б менше схильних до помилок просто встановити чотири змінні.
NitroxDM

Назва запитання - це справді важливе питання, але приклад коду жахливий. Як показує прийнята відповідь, у вашому прикладі вам не потрібно було "йти". Результат полягає в тому, що прийнята відповідь не відповідає на запитання у вашому заголовку.
Грег Вудс

Відповіді:


31

goКоманда використовуються для поділу коду на окрему партію. Якщо це саме те, що ви хочете зробити, тоді вам слід це використовувати, але це означає, що партії насправді окремі, і ви не можете ділитися змінними між ними.

У вашому випадку рішення просте; Ви можете просто видалитиgo твердження, вони не потрібні в цьому коді.

Примітка: Ви не можете використовувати змінну в useоператорі, це має бути ім'я бази даних.


1
Деякі оператори SQL повинні бути першим оператором у блоці (область між операторами GO). Наприклад: СТВОРИТИ ПРОЦЕДУРУ або СТВОРИТИ ФУНКЦІЮ, обоє мають відбуватися перед будь-якими іншими операторами - або у верхній частині сценарію, або безпосередньо після оператора GO (примітка: пробіли та коментарі дозволяються перед цими твердженнями). При запуску сценаріїв, де такі оператори повинні відбуватися за іншою логікою, необхідні оператори GO. Але я повинен погодитись, що в більшості випадків заяви GO можна видалити.
Зарефет

@Zarepheth: Гарна думка. Це не потрібно в цьому конкретному коді, але корисно знати, що вони можуть знадобитися в деяких випадках.
Guffa

1
Чому голос проти? Якщо ви не поясніть, що саме ви вважаєте неправильним, це не може покращити відповідь.
Guffa

2
@jwize: Ні, вам не потрібно їх відокремлювати, це можна зробити в тому ж блоці.
Гуффа

1
@Ben: goКоманда використовується для розділення коду на окремі пакети. Якщо це те, що ви хочете зробити, то вам слід це використовувати, але це означає, що партії насправді окремі, і ви не можете ділитися змінними між ними.
Guffa,

127

Використовуйте тимчасову таблицю:

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
чудова відповідь ... ви насправді ВІДПОВІДАЛИ НА ЗАДАННЕ запитання, а не працювали навколо.
Кос Калліс,

1
Це правильна відповідь. Гарне рішення. Крім того, приємно, що якщо ви використовуєте велику кількість змінних, вони знаходяться в одній легкодоступній таблиці, без прокрутки вгору та вниз SP, що шукає ваші декларації.
ColinMac

15

Я віддаю перевагу цій відповіді з цього питання Глобальні змінні з GO

Що має додаткову перевагу в тому, що ти можеш робити те, що ти спочатку хотів зробити.

Застереження полягає в тому, що вам потрібно ввімкнути режим SQLCMD (у розділі Запит-> SQLCMD) або увімкнути його за замовчуванням для всіх вікон запитів (Інструменти-> Параметри, потім Результати запитів-> За замовчуванням, відкрити нові запити в режимі SQLCMD)

Тоді ви можете використовувати наступний тип коду (повністю відірваний від тієї самої відповіді Оскаром Е. Фракседасом Тормо )

--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, і для того, щоб вихід виводився до файлу, вам потрібно виконати GO, тому такий: синтаксис setvar необхідний для заміни нормальних змінних у цій ситуації, оскільки ви ' знову змушені поділяти речі на партії.
Anssssss

Чудово! Це насправді слід позначити як справжню правильну відповідь!
Поліція SQL

3

Якщо ви використовуєте SQL Server, ви можете встановити глобальні змінні для цілих сценаріїв, таких як:

:setvar sourceDB "lalalallalal"

і використовувати пізніше в сценарії як:

$(sourceDB)

Переконайтеся, що режим SQLCMD увімкнено в Server Managment Studi, це можна зробити за допомогою верхнього меню Клацніть Запит і увімкніть режим SQLCMD.

Більше по темі можна знайти тут: Документація MS


1

Не впевнений, якщо це допомагає

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

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

execute sp_executesql @t

1

Температурні таблиці зберігаються над операторами GO, тому ...

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

Це не красиво, але це працює


1

Створіть власні збережені процедури, які зберігають / завантажують до тимчасової таблиці.

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

Тоді ви можете використовувати це:

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)))

Вихід:

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

Ви також можете використовувати такі:

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

Вихід exec dbo.MyVariableList:

Name    Value
test    42

Виявляється, можливість перерахувати всі змінні в таблиці насправді досить корисна. Тож навіть якщо ви не завантажуєте змінну пізніше, вона чудово підходить для налагодження, щоб бачити все в одному місці.

Тут використовується тимчасова таблиця з ## префіксом, тому її достатньо, щоб пережити оператор GO. Він призначений для використання в одному сценарії.

І збережені процедури:

-- 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

Якщо вам просто потрібен двійковий файл так / ні (наприклад, якщо стовпець існує), тоді ви можете використати SET NOEXEC ONдля відключення виконання операторів. SET NOEXEC ONпрацює через GO (по партіях). Але пам'ятайте , щоб повернути EXEC спину з SET NOEXEC OFFв кінці сценарію.

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

Це компілює оператори, але не виконує їх. Тож ви все одно отримаєте "помилки компіляції", якщо посилаєтесь на схему, яка не існує. Отже, це працює, щоб "вимкнути" сценарій 2-го запуску (що я роблю), але не працює, щоб вимкнути частини сценарію при 1-му запуску, оскільки ви все одно отримаєте помилки компіляції, якщо посилання на стовпці або таблиці не ще не існує.


0

Ви можете скористатися NOEXEC, виконавши наступні кроки:

Створити таблицю

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

вставити версії процедур і вказівник на версію в тимчасову таблицю #temp_procedure_version

--приклад вказівника на процедуру_версії

вставити у temp_procedure_versionзначення (1.0, "перша версія")

вставити у temp_procedure_versionзначення (2.0, "остаточна версія")

потім отримати версію процедури, ви можете використовувати де умова, як у наступному твердженні

Виберіть @ProcedureVersion=ProcedureVersionз #temp_procedure_versionде pointer='first version'

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

--вставте тут процедуру версії 1.0

Створити процедуру версії 1.0 як .....

SET NOEXEC OFF -- execution is ON

Виберіть @ProcedureVersion=ProcedureVersionз #temp_procedure_versionде покажчика = «остаточного варіанту»

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

Створити процедуру версії 2.0 як .....

SET NOEXEC OFF -- execution is ON

--пустіть часову таблицю

Падіння таблиці #temp_procedure_version

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.