我正在尝试运行一个选择查询,该查询在 where 子句中接收@Sites 变量。目前的查询返回空,因为以下行
AND S.[Name] IN (@Sites)
Run Code Online (Sandbox Code Playgroud)
未按预期处理。下面是查询的摘录:
SET QUOTED_IDENTIFIER OFF
DECLARE @Month int
, @Sites varchar(MAX) = null
SET @Month = 8
SET @Sites = 'Bayside;Collaborative'
SET @Sites = "'" + REPLACE(@Sites,';',"','") + "'"
SELECT
CV.[Id] AS Id
, ...
, S.[Name] AS [Site]
, ...
FROM
[CalendarViews] CV
INNER JOIN [Sites] S ON S.[Id] = CV.[SiteId]
WHERE
MONTH(CV.[DateAllocation]) = @Month
AND S.[Name] IN (@Sites)
ORDER BY
S.[Name]
Run Code Online (Sandbox Code Playgroud)
当我运行查询替换
AND S.[Name] IN (@Sites)
Run Code Online (Sandbox Code Playgroud)
为了
AND S.[Name] IN ('Bayside','Collaborative')
Run Code Online (Sandbox Code Playgroud)
查询按预期工作。有人可以告诉我我缺少什么吗?谢谢你。
@Sites
是一个字符串,而不是一个数组。所以你实际上是在寻找:
S.[Name] IN ('''Bayside'',''Collaborative''')
-------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- this is one single string
Run Code Online (Sandbox Code Playgroud)
我强烈建议,不要传入逗号或分号分隔的字符串,而是传入表值参数。首先,在您的数据库中创建它:
CREATE TYPE dbo.Sites AS TABLE(Site NVARCHAR(255));
Run Code Online (Sandbox Code Playgroud)
然后你的程序会说(省略不太相关的位):
ALTER PROCEDURE dbo.ProcedureName
@Sites dbo.Sites READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT ...
FROM dbo.Sites AS s
INNER JOIN @Sites AS tvp
ON s.[Name] = tvp.Site;
END
GO
Run Code Online (Sandbox Code Playgroud)
然后您的代码将传递一个结构化参数(我假设这组站点最初来自 DataTable 或其他一些集合):
SqlCommand cmd = new SqlCommand("dbo.ProcedureName", conn);
c2.CommandType = CommandType.StoredProcedure;
SqlParameter tvp = cmd.Parameters.AddWithValue("@Sites", DataTableName);
tvp.SqlDbType = SqlDbType.Structured;
...
Run Code Online (Sandbox Code Playgroud)
如果您真的想以缓慢、老式的方式执行此操作,您可以创建一个分割字符串的 UDF:
CREATE FUNCTION dbo.SplitStrings_XML
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(@List, @Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
Run Code Online (Sandbox Code Playgroud)
然后你的查询是(再次省略了不太相关的位):
INNER JOIN dbo.SplitStrings_XML(@Sites, N';') AS f
ON s.[Name] = f.Item;
Run Code Online (Sandbox Code Playgroud)
现在,XML 在这里可能不是安全的方法,但它是最简单的复制方法,无需提供更慢的方法或辅助对象(如数字表)。对于其他替代方案,以及更多关于为什么你不想这样做的信息,请参阅:
归档时间: |
|
查看次数: |
500 次 |
最近记录: |