ประกาศตัวแปรสำหรับสตริงการสืบค้น


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)

Dynamic SQL เป็นเพียงคำสั่ง SQL ซึ่งประกอบเป็นสตริงก่อนที่จะดำเนินการ ดังนั้นการต่อสายอักขระตามปกติจึงเกิดขึ้น Dynamic SQL จำเป็นเมื่อใดก็ตามที่คุณต้องการทำบางสิ่งในไวยากรณ์ SQL ที่ไม่ได้รับอนุญาตเช่น:

  • พารามิเตอร์เดียวเพื่อแสดงรายการค่าที่คั่นด้วยเครื่องหมายจุลภาคสำหรับอนุประโยค IN
  • ตัวแปรเพื่อแสดงทั้งค่าและไวยากรณ์ SQL (IE: ตัวอย่างที่คุณระบุ)

EXEC sp_executesql ช่วยให้คุณสามารถใช้พารามิเตอร์การผูก / จัดเตรียมดังนั้นคุณจึงไม่ต้องกังวลกับการหลีกเลี่ยงเครื่องหมายคำพูดเดี่ยว / ฯลฯ สำหรับการโจมตีด้วยการฉีด SQL


ฉันคิดว่านี่เป็นคำตอบที่ถูกต้องที่สุด เมื่อเร็ว ๆ นี้ฉันใช้ SQL Server 2005 และการใช้ตัวแปรสำหรับการแทนที่สตริงการสืบค้นอย่างที่ OP ต้องการนั้นเป็นไปไม่ได้ (สร้างข้อผิดพลาดทางไวยากรณ์) ตัวแปรไม่สามารถรวมทั้งไวยากรณ์และชนิดข้อมูลดังที่ @Ponies กล่าว Dynamic 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

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

ฉันจะชี้ให้เห็นว่าในบทความที่เชื่อมโยงในคำตอบอันดับต้น ๆ คำสาปและพรของไดนามิก SQLผู้เขียนระบุว่าคำตอบคือไม่ใช้ไดนามิก SQL เลื่อนไปจนเกือบสุดเพื่อดูสิ่งนี้

จากบทความ: "วิธีการที่ถูกต้องคือการคลายรายการลงในตารางด้วยฟังก์ชันที่ผู้ใช้กำหนดเองหรือขั้นตอนการจัดเก็บ"

แน่นอนเมื่อรายการอยู่ในตารางคุณสามารถใช้การเข้าร่วมได้ ฉันไม่สามารถแสดงความคิดเห็นโดยตรงกับคำตอบที่ได้รับคะแนนสูงสุดดังนั้นฉันจึงเพิ่มความคิดเห็นนี้


สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม เมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด ๆ ; แทนที่จะให้คำตอบที่ไม่จำเป็นต้องชี้แจงจากผู้ถาม - จากรีวิว
Sam M

ขอบคุณแซม ฉันจะอัปเดตความคิดเห็นของฉันพร้อมรายละเอียดเมื่อฉันใช้สิ่งที่ Erland Sommarskog แนะนำ ฉันจะอ้างอิงชื่อเขาด้วยเพราะเขาสมควรได้รับเครดิตสำหรับคำตอบ
DavidG
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.