我试图在IN子句中传递一个变量,并在谷歌搜索解决方案中进行了以下操作,但出现错误。任何帮助和/或指示,将不胜感激。
首先列出我的代码,然后在下面找到错误。
我的代码:
DECLARE @OwnerSysID varchar(500)
SET @OwnerSysID = '3, 3476, 3511'
DECLARE @sql nvarchar(4000)
SET @sql = 'Select AllPosiable.UserID, AllPosiable.AgentSysID, 0' +
'From (' +
'Select AgentSysID, UserID' +
'From (' +
'Select AGT_Agent.AgentSysID' +
'From AGT_Agent' +
'Where OwnerSysID IN ('+@OwnerSysID+')' +
'AND AgentName NOT LIKE %Texas State Low Cost%' +
'AND AgentName NOT LIKE %TSLC%' +
') as AgentIDs ' +
'Full Join (' +
'Select DISTINCT IW_UserAgentRelationship.UserID' +
'From AGT_Agent' +
'Left Join IW_UserAgentRelationship' +
'On IW_UserAgentRelationship.AgentID = AGT_Agent.AgentSysID' +
'Where OwnerSysID IN ('+@OwnerSysID+')' +
'And IW_UserAgentRelationship.isDefault = 1' +
'AND AgentName NOT LIKE %Texas State Low Cost%' +
'AND AgentName NOT LIKE %TSLC%' +
') As UserIDs On 1=1' +
') as AllPosiable' +
'Left Join IW_UserAgentRelationship' +
'On IW_UserAgentRelationship.AgentID = AllPosiable.AgentSysID' +
'And IW_UserAgentRelationship.UserID = AllPosiable.UserID' +
'Where IW_UserAgentRelationship.AgentID Is NULL'
EXEC sp_executesql @sql;
错误:
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'Select'.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'OwnerSysID'.
Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'Join'.
谢谢。
答案 0 :(得分:3)
这没有将变量传递给IN()子句。这是直接注入易受攻击的字符串连接,因此请非常小心使用它。
但是问题在这里:
SET @sql = 'Select AllPosiable.UserID, AllPosiable.AgentSysID, 0' +
'From (' +
第一行结尾0
之后的字符串中没有空格,第二行开头的单词From
之前没有空格,并且它们之间的换行符不属于结果字符串。您最终会得到以下结果:
Select AllPosiable.UserID, AllPosiable.AgentSysID, 0From (...
尝试一下:
SET @sql = 'Select AllPosiable.UserID, AllPosiable.AgentSysID, 0' +
' From (' +
并确保在每个换行符处都在执行类似的操作。
此外,您需要查看以下摘录:
'AND AgentName NOT LIKE %Texas State Low Cost%' +
表达式%Texas State Low Cost%
不会成为结果SQL代码中字符串文字的一部分。您需要这样做:
'AND AgentName NOT LIKE ''%Texas State Low Cost%''' +
并再次确保SQL语句中的所有字符串文字都得到类似的处理。
答案 1 :(得分:2)
查询中有多个问题。试试这个:
SET @sql = N' -- strings should nvarchar for sp_executesql
Select AllPosiable.UserID, AllPosiable.AgentSysID, 0
From (Select AgentSysID, UserID
From (Select AGT_Agent.AgentSysID
From AGT_Agent
Where OwnerSysID IN (@OwnerSysID) and
AgentName NOT LIKE ''%Texas State Low Cost%'' and
AgentName NOT LIKE ''%TSLC%''
) AgentIDs Full Join
(Select DISTINCT IW_UserAgentRelationship.UserID
From AGT_Agent Left Join
IW_UserAgentRelationship
On IW_UserAgentRelationship.AgentID = AGT_Agent.AgentSysID
Where OwnerSysID IN (@OwnerSysID) and
IW_UserAgentRelationship.isDefault = 1 and
AgentName NOT LIKE ''%Texas State Low Cost%'' and
AgentName NOT LIKE ''%TSLC%''
) UserIDs
On 1 = 1
) AllPosiable Left Join
IW_UserAgentRelationship
On IW_UserAgentRelationship.AgentID = AllPosiable.AgentSysID and
IW_UserAgentRelationship.UserID = AllPosiable.UserID
Where IW_UserAgentRelationship.AgentID Is NULL
' ;
SET @sql = replace(@sql, n'@OwnerSysID', @OwnerSysID)
EXEC sp_executesql @sql;
您的基本问题是不了解字符串可以跨越SQL Server中的多行。这意味着您不必将一堆不同的线连接在一起。在您的情况下,您将关键字合并在一起,因此SQL是无法理解的。如果您已经打印出@sql
,这将是显而易见的。
另一个问题是like
模式没有被单引号引起来。在字符串中,这些需要重复。
我没有看查询本身的逻辑,但是我真的怀疑full join
是否必要。
答案 2 :(得分:1)
我猜您正在采用动态sql路由,只是因为您需要将@OwnerSysID作为逗号分隔的值传递给IN()
如果是这种情况,请使用TVF传递带有逗号分隔值的变量,而不使用动态sql。
中提到了这种方法基本上,您需要一个表值函数,该函数将处理@OwnerSysID并将其值转换为行(借助XML技术),然后在IN()
所需功能:
CREATE FUNCTION Split(@String VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
(
SELECT LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))) MyString
FROM (
SELECT CAST('<XMLRoot><RowData>' + REPLACE(@String,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) MyString
) D
CROSS APPLY MyString.nodes('/XMLRoot/RowData')m(n)
)
然后您可以像这样在查询中使用它:
OwnerSysID IN (SELECT * FROM dbo.Split(@OwnerSysID))
使用这种方法,您不需要动态sql,只需一个普通的查询就足够了。