쿼리 문자열에 대한 변수 선언


92

MS SQL Server 2005에서이 작업을 수행하는 방법이 있는지 궁금합니다.

  DECLARE @theDate varchar(60)
  SET @theDate = '''2010-01-01'' AND ''2010-08-31 23:59:59'''

  SELECT    AdministratorCode, 
            SUM(Total) as theTotal, 
            SUM(WOD.Quantity) as theQty, 
            AVG(Total) as avgTotal, 
            (SELECT SUM(tblWOD.Amount)
                FROM tblWOD
                JOIN tblWO on tblWOD.OrderID = tblWO.ID
                WHERE tblWO.Approved = '1' 
                AND tblWO.AdministratorCode = tblWO.AdministratorCode
                AND tblWO.OrderDate BETWEEN @theDate
            )
 ... etc

이것이 가능합니까?


답변:


97

가능하지만 동적 SQL을 사용해야합니다. 계속하기 전에 동적 SQL의 저주와 축복을
읽는 것이 좋습니다 .

DECLARE @theDate varchar(60)
SET @theDate = '''2010-01-01'' AND ''2010-08-31 23:59:59'''

DECLARE @SQL VARCHAR(MAX)  
SET @SQL = 'SELECT AdministratorCode, 
                   SUM(Total) as theTotal, 
                   SUM(WOD.Quantity) as theQty, 
                   AVG(Total) as avgTotal, 
                  (SELECT SUM(tblWOD.Amount)
                     FROM tblWOD
                     JOIN tblWO on tblWOD.OrderID = tblWO.ID
                    WHERE tblWO.Approved = ''1''
                      AND tblWO.AdministratorCode = tblWO.AdministratorCode
                      AND tblWO.OrderDate BETWEEN '+ @theDate +')'

EXEC(@SQL)

동적 SQL은 실행되기 전에 문자열로 구성된 SQL 문입니다. 따라서 일반적인 문자열 연결이 발생합니다. 다음과 같이 허용되지 않는 SQL 구문을 수행하려면 동적 SQL이 필요합니다.

  • IN 절에 대해 쉼표로 구분 된 값 목록을 나타내는 단일 매개 변수
  • 값과 SQL 구문을 모두 나타내는 변수 (IE : 제공 한 예)

EXEC sp_executesql bind / preparedstatement 매개 변수를 사용할 수 있으므로 SQL 인젝션 공격을 위해 작은 따옴표 등을 이스케이프 처리 할 필요가 없습니다.


이것이 가장 정답이라고 생각합니다. 나는 최근에 SQL Server 2005를 사용하고 있으며 OP가 원하는 쿼리 문자열 교체를 위해 변수를 사용하는 것은 불가능합니다 (구문 오류 발생). @Ponies가 말했듯이 변수에는 구문과 데이터 유형이 모두 포함될 수 없습니다. 동적 SQL은 문자열을 통해 SQL Server에서 쿼리를 작성하는 방법입니다. 인용문과 유형에주의하는 것을 잊지 마십시오! 실행하는 문자열에는 datetime 또는 int와 같은 일부 유형이 문자열 연결을 위해 변환되거나 캐스트되어야합니다.
RoboBear

52
DECLARE @theDate DATETIME
SET @theDate = '2010-01-01'

그런 다음이 논리를 사용하도록 쿼리를 변경합니다.

AND 
(
    tblWO.OrderDate > DATEADD(MILLISECOND, -1, @theDate) 
    AND tblWO.OrderDate < DATEADD(DAY, 1, @theDate)
)

2
잠시만 요. 질문에 두 개의 다른 날짜가 명확하게 표시되면 대답이 될 수 없습니다. 결국 @StealthRT에서 어떻게 코딩 했습니까? 답변의 '2010-08-31'날짜는 어디에 있습니까? 또한이 질문은 DECLARE 변수를 사용하여 코드를 다른 SELECT 문으로 대체 할 수 있는지 명확하게 묻습니다. 정답은 아래와 같습니다.
Fandango68 2015 년

2

EXEC 사용

다음 예제를 사용하여 SQL 문을 작성할 수 있습니다.

DECLARE @sqlCommand varchar(1000)
DECLARE @columnList varchar(75)
DECLARE @city varchar(75)
SET @columnList = 'CustomerID, ContactName, City'
SET @city = '''London'''
SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = ' + @city
EXEC (@sqlCommand)

sp_executesql 사용

이 접근 방식을 사용하면 쿼리에 전달되는 데이터 값이 올바른 데이터 유형인지 확인하고 더 많은 따옴표를 사용할 수 없습니다.

DECLARE @sqlCommand nvarchar(1000)
DECLARE @columnList varchar(75)
DECLARE @city varchar(75)
SET @columnList = 'CustomerID, ContactName, City'
SET @city = 'London'
SET @sqlCommand = 'SELECT ' + @columnList + ' FROM customers WHERE City = @city'
EXECUTE sp_executesql @sqlCommand, N'@city nvarchar(75)', @city = @city

참고


1

나는 최고 등급의 답변 The Curse and Blessings of Dynamic SQL에 링크 된 기사 에서 저자가 대답은 동적 SQL을 사용하지 않는 것이라고 언급했습니다. 이것을 보려면 거의 끝까지 스크롤하십시오.

기사에서 "올바른 방법은 사용자 정의 함수 또는 저장 프로 시저가있는 테이블에 목록을 압축 해제하는 것입니다."

물론 목록이 테이블에 있으면 조인을 사용할 수 있습니다. 최고 평점 답변에 직접 댓글을 달 수 없어서이 댓글을 추가했습니다.


이것은 질문에 대한 답을 제공하지 않습니다. 충분한 평판얻으면 모든 게시물댓글 수 있습니다 . 대신 질문자의 설명이 필요하지 않은 답변을 제공하세요 . - 리뷰에서
Sam M

감사합니다 샘. Erland Sommarskog가 제안한 것을 구현하면 내 의견을 세부 사항으로 업데이트 할 것입니다. 나는 또한 그가 대답에 대한 크레딧을받을 자격이 있기 때문에 그를 이름으로 언급 할 것입니다.
DavidG
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.