【问题标题】:sql stored procedure conditional where clause returning syntax errorsql存储过程条件where子句返回语法错误
【发布时间】: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


【解决方案1】:

由于您将参数值嵌入到查询变量中,因此无需将参数添加到 sp_executesql 调用中,因此应该可以:

EXEC sp_executesql @sSQL

代替:

EXEC sp_executesql @sSQL, @Depot, @Class

这是一个完整的 DDL 语句示例 - 将最后一行换成原始版本,你会得到语法错误。

CREATE TABLE EmployeeMaster (EmployeeNumber INT, EmployeeSurname VARCHAR(25), EmployeeInitials VARCHAR(10), FrequencyDesc VARCHAR(25), EmpCode VARCHAR(25), Depot VARCHAR(25), EmployeeLeft VARCHAR(1))
CREATE TABLE PayrollFrequency (DescCode VARCHAR(25), FrequencyDesc VARCHAR(25))
CREATE TABLE EmployeeDrivingLicence (EmpCode VARCHAR(25), Class1 VARCHAR(1), Package VARCHAR(1), Tanks VARCHAR(1))
ALTER TABLE EmployeeDrivingLicence ADD ExpiryDate DATETIME
CREATE TABLE Depot (Depot VARCHAR(25), DescCode VARCHAR(25), DepotDepotDescription VARCHAR(25))

CREATE PROCEDURE [TTR_HazDriver]
@Depot nvarchar(50),
@Class nvarchar(1)

AS
BEGIN

...

EXEC sp_executesql @sSQL
END
GO

EXEC [TTR_HazDriver] 'test', 'P'

【讨论】:

    猜你喜欢
    • 2010-12-21
    • 2015-11-21
    • 2015-01-29
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多