【发布时间】:2018-05-01 06:34:57
【问题描述】:
我有以下带有 2 个参数的存储过程。 @Class 参数可以有 11 个值中的任何一个。根据值,where 子句查看不同的列。
该程序编译正常,如果我将打印内容复制并粘贴到新的查询窗口中,它运行良好,但如果我执行该程序,我会在“Bristol”附近收到不正确的语法错误消息,但无法弄清楚我需要什么尽管在此处和其他网页上查看,仍要进行修复。任何帮助将不胜感激
ALTER PROCEDURE [TTR_HazDriver]
@Depot nvarchar(50),
@Class nvarchar(1)
AS
BEGIN
DECLARE @Where nvarchar(1000)
DECLARE @sSql nvarchar(MAX)
DECLARE @Order nvarchar(1000)
SET @sSql = '
SELECT EM.EmployeeNumber
, EM.EmployeeSurname
, EM.EmployeeInitials
, D.Depot
, EDL.Class1
, EDL.Class2
, EDL.Class3
, EDL.Class4
, EDL.Class5
, EDL.Class6
, EDL.Class7
, EDL.Class8
, EDL.Class9
, CONVERT(VARCHAR(10),EDL.ExpiryDate, 103) ExpiryDate
, EDL.Tanks
, EDL.Package
FROM EmployeeMaster EM
LEFT OUTER JOIN PayrollFrequency PF ON EM.FrequencyDesc = PF.DescCode
INNER JOIN EmployeeDrivingLicence EDL ON EM.EmpCode = EDL.EmpCode
LEFT OUTER JOIN Depot D ON EM.Depot = D.DescCode'
SET @Where = '
WHERE (D.Depot = ''' + @Depot + ''' OR ''' + @Depot + ''' IS NULL)
AND EM.EmployeeLeft = ''N''
AND PF.FrequencyDesc = ''Weekly'''
SET @Order = '
ORDER BY D.DepotDepotDescription
, EDL.ExpiryDate'
IF @Class = '1'
SET @Where = @Where + ' AND EDL.Class1 = ''Y'''
IF @Class = '2'
SET @Where = @Where + ' AND EDL.Class2 = ''Y'''
IF @Class = '3'
SET @Where = @Where + ' AND EDL.Class3 = ''Y'''
IF @Class = '4'
SET @Where = @Where + ' AND EDL.Class4 = ''Y'''
IF @Class = '5'
SET @Where = @Where + ' AND EDL.Class5 = ''Y'''
IF @Class = '6'
SET @Where = @Where + ' AND EDL.Class6 = ''Y'''
IF @Class = '7'
SET @Where = @Where + ' AND EDL.Class7 = ''Y'''
IF @Class = '8'
SET @Where = @Where + ' AND EDL.Class8 = ''Y'''
IF @Class = '9'
SET @Where = @Where + ' AND EDL.Class9 = ''Y'''
IF @Class = 'T'
SET @Where = @Where + ' AND EDL.Tanks = ''Y'''
IF @Class = 'P'
SET @Where = @Where + ' AND EDL.Package = ''Y'''
SET @sSql = @sSql + @Where + @Order
PRINT @sSql
EXEC sp_executesql @sSQL, @Depot, @Class
END
打印语句产生以下查询:
SELECT EM.EmployeeNumber
, EM.EmployeeSurname
, EM.EmployeeInitials
, D.Depot
, EDL.Class1
, EDL.Class2
, EDL.Class3
, EDL.Class4
, EDL.Class5
, EDL.Class6
, EDL.Class7
, EDL.Class8
, EDL.Class9
, CONVERT(VARCHAR(10),EDL.ExpiryDate, 103) ExpiryDate
, EDL.Tanks
, EDL.Package
FROM EmployeeMaster EM
LEFT OUTER JOIN PayrollFrequency PF ON EM.FrequencyDesc = PF.DescCode
INNER JOIN EmployeeDrivingLicence EDL ON EM.EmpCode = EDL.EmpCode
LEFT OUTER JOIN Depot D ON EM.DepotDepotDescription = D.DescCode
WHERE (D.DepotDepotDescription = 'Bristol' OR 'Bristol' IS NULL)
AND PF.FrequencyDesc = 'Weekly'
AND EDL.Class3 = 'Y'
ORDER BY D.Depot
, EDL.ExpiryDate
【问题讨论】:
-
生成的查询与存储过程中的代码匹配不佳。
EM.EmployeeMasterLeft从哪里来?FrequencyDesc?,EDL.ExpiryDate >= {ts '2007-01-01 00:00:00'}? -
使用适当的软件(MySQL、Oracle、DB2...)和版本标记数据库问题很有帮助,例如
sql-server-2014。语法和功能的差异通常会影响答案。请注意,tsql缩小了选择范围,但没有指定数据库。 -
已经编辑了我的原始代码
-
这种“动态”存储过程没有任何好处。但是有很多缺点,比如允许 SQL 注入、导致语法错误、意外的转换错误。
Catch-all像@Depot这样的参数也是一个坏主意,因为它们会导致执行计划效率低下。整个SELECT FROM部分可以由单个视图替换。客户端的 LINQ 可以安全地添加额外的 WHERE 和 ORDER BY 子句
标签: sql-server tsql stored-procedures sql-server-2014