이동 중에 변수를 유지하는 방법이 있습니까?


83

이동 중에 변수를 유지하는 방법이 있습니까?

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의 '사용 @bob'라인에 대한 질문을.


DB 이름으로 테이블 이름을 한정해야하는 이유는 무엇입니까? 이 질문 전에 비슷한 질문이 제기 된 것 같습니다.
shahkalpesh

그리고 이와 같은 변수의 데이터베이스 이름으로 테이블 이름을 한정 할 방법이 없습니다. USE 문과 함께 변수를 사용하는 것에 대한 이전 질문에서, 나는 그가 테이블로 끌리는 모든 고통과 함께 동적 SQL에서 모든 것을 수행해야 할 것이라고 생각합니다.
Lasse V. Karlsen

실제 스크립트는 4 개의 서로 다른 데이터베이스를 통합합니다. dbName1, dbName2, dbName3 및 dbName4를 찾아 바꾸는 지침에 대해 설명했습니다. 클라이언트가 4 개의 변수 만 설정하면 오류가 덜 발생한다고 생각했습니다.
NitroxDM

질문 제목은 정말 중요한 질문이지만 예제 코드는 끔찍합니다. 받아 들여진 대답에서 알 수 있듯이 예제에서 'go'가 필요하지 않았습니다. 그 결과 수락 된 답변이 제목의 질문에 대한 답변이 아닙니다.
Greg Woods

답변:


31

go명령은 코드를 별도의 배치로 분할하는 데 사용됩니다. 이것이 정확히 원하는 작업이라면 사용해야하지만 배치가 실제로 분리되어 있고 둘 사이에 변수를 공유 할 수 없음을 의미합니다.

귀하의 경우 솔루션은 간단합니다. go명령문을 제거 할 수 있으며 해당 코드에서 필요하지 않습니다.

참고 : use문 에서 변수를 사용할 수 없으며 데이터베이스의 이름이어야합니다.


1
일부 SQL 문은 블록 (GO 문 사이의 영역)에서 첫 번째 문이어야합니다. 예 : CREATE PROCEDURE 또는 CREATE FUNCTION은 스크립트 상단 또는 GO 문 바로 뒤에있는 다른 문 앞에 모두 발생해야합니다 (참고 : 이러한 문 앞에 공백과 주석이 허용됨). 이러한 문이 다른 논리 다음에 발생해야하는 스크립트를 실행할 때는 GO 문이 필요합니다. 그러나 대부분의 경우 GO 문을 제거 할 수 있다는 데 동의해야합니다.
Zarepheth

@Zarepheth : 좋은 지적입니다. 이 특정 코드에서는 필요하지 않지만 경우에 따라 필요할 수 있음을 아는 것이 유용합니다.
Guffa 2013

1
왜 반대 투표입니까? 잘못되었다고 생각하는 것이 무엇인지 설명하지 않으면 답을 개선 할 수 없습니다.
Guffa

2
@jwize : 아니요, 분리 할 필요가 없습니다. 동일한 블록에서 수행 할 수 있습니다.
Guffa

1
@Ben :이 go명령은 코드를 개별 배치로 분할하는 데 사용됩니다. 그것이 당신이하고 싶은 일이라면 그것을 사용해야하지만 그것은 배치가 실제로 분리되어 있고 그들 사이에 변수를 공유 할 수 없다는 것을 의미합니다.
Guffa 2015-06-24

128

임시 테이블 사용 :

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
훌륭한 대답 ... 당신은 실제로 해결 방법을 제공하지 않고 질문에 대답했습니다.
Cos Callis

1
이것이 정답입니다. 좋은 솔루션입니다. 또한 많은 수의 변수를 사용하는 경우 모두 쉽게 액세스 할 수있는 하나의 테이블에 있으며 선언을 찾기 위해 SP를 위아래로 스크롤하지 않아도됩니다.
ColinMac

15

내가 선호하는 이 질문에서 답을 GO 글로벌 변수

원래하고 싶었던 일을 할 수 있다는 추가적인 이점이 있습니다.

주의 할 점은 SQLCMD 모드 (쿼리-> SQLCMD 아래)를 켜거나 모든 쿼리 창에 대해 기본적으로 켜야한다는 것입니다 (도구-> 옵션 다음 쿼리 결과-> 기본적으로 SQLCMD 모드에서 새 쿼리 열기).

그런 다음 다음 유형의 코드를 사용할 수 있습니다 ( Oscar E. Fraxedas Tormo의 동일한 답변에서 완전히 찢어짐 )

--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 모드에서 쿼리 출력을 다른 파일 (: out filename)으로 리디렉션하고 출력을 파일로 플러시하려면 GO를 실행해야하므로이 : setvar 구문은 해당 상황에서 일반 변수를 대체하는 데 필요합니다 항목을 일괄로 분할해야했습니다.
Anssssss

큰! 이것은 실제로 진짜 정답으로 표시되어야합니다!
SQL 경찰

3

SQL Server를 사용하는 경우 다음과 같은 전체 스크립트에 대한 전역 변수를 설정할 수 있습니다.

:setvar sourceDB "lalalallalal"

나중에 스크립트에서 다음과 같이 사용하십시오.

$(sourceDB)

Server Managment Studi에서 SQLCMD 모드가 켜져 있는지 확인하십시오. 상단 메뉴를 통해 수행 할 수 있습니다. 쿼리를 클릭하고 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 ONGO (배치 전체)에서 작동합니다. 그러나 에 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

이것은 명령문을 컴파일하지만 실행하지는 않습니다. 따라서 존재하지 않는 스키마를 참조하면 "컴파일 오류"가 발생합니다. 따라서 스크립트 두 번째 실행 (내가하는 일)을 "끄기"위해 작동하지만 첫 번째 실행에서 스크립트의 일부를 끄는 것은 작동하지 않습니다. 아직 존재하지 않습니다.


0

아래 단계에 따라 NOEXEC를 사용할 수 있습니다.

테이블 만들기

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

프로 시저 버전과 버전에 대한 포인터를 임시 테이블에 삽입 #temp_procedure_version

--example procedure_version 포인터

temp_procedure_version값에 삽입 (1.0, '첫 번째 버전')

temp_procedure_version값에 삽입 (2.0, '최종 버전')

그런 다음 프로 시저 버전을 검색하면 다음 문과 같이 where 조건을 사용할 수 있습니다.

어디 @ProcedureVersion=ProcedureVersion에서 선택#temp_procedure_versionpointer='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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.