我正在使用SQL Server 2000并且在SQL代码块(下面)中遇到了一个奇怪的问题:
用户可以输入“GM”作为可能的参数或“F”。如果用户在存储的proc查询字符串中输入“GM”作为参数,我需要AutoDivision包含GMC,CAD,CHE,SAT
declare @AutoDivision as varchar(15)
set @AutoDivision = 'GM'
if @AutoDivision = 'GM'
Begin
Select @AutoDivision = '''Cad'', ''GMC'', ''Sat'', ''Che'''
End
SELECT
oh.OrderNumber, lg.[lgh_number]
FROM
[dbo].[OrderHeader] oh (NOLOCK)
INNER JOIN
[dbo].[DistrctHeader] lg (NOLOCK) ON oh.[inv_number] = lg.[inv_number]
INNER JOIN
[dbo].[DealerCompany] c (NOLOCK) ON c.cmp_id = LEFT(oh.[ordernumber],3)
INNER JOIN
[dbo].[divisionXREF] x (NOLOCK) ON x.Division = c.comp_revtype
WHERE
oh.ord_number = '113-889257'
AND x.AutoDivision IN (@AutoDivision)
--AND x.AutoDivision IN ('Cad', 'Sat', 'GMC', 'Che')
AND lg.[lgh_outstatus] IN ('AVAIL', 'PLAN', 'DISP', 'STRTD', 'PEND','COMP')
但是,当我运行下面的代码时,我没有找回任何记录。
当我取消注释代码行时
--AND x.AutoDivision IN ('Cad', 'Sat', 'GMC', 'Che')
它有效(我得到了一条记录)。
当我做print 'AND x.AutoDivision IN (' + cast(@AutoDivision as varchar) + ')'
时
我回来了AND x.AutoDivision IN ('Cad', 'GMC', 'Sat', 'Che')
我在这里缺少什么?
答案 0 :(得分:10)
您不能使用单个变量来表示SQL中的逗号分隔的IN参数列表 - Oracle,MySQL,SQL Server ......无关紧要。
要使此变量方法起作用,您需要使用动态SQL,以便能够首先将查询创建为字符串(使用串联从变量中获取IN参数),然后执行查询语句:
DECLARE @cmd VARCHAR(1000)
SET @cmd = 'SELECT oh.OrderNumber,
lg.[lgh_number]
FROM [dbo].[OrderHeader] oh (NOLOCK)
JOIN [dbo].[DistrctHeader] lg (NOLOCK) ON oh.[inv_number] = lg.[inv_number]
JOIN [dbo].[DealerCompany] c (NOLOCK) ON c.cmp_id = LEFT(oh.[ordernumber],3)
JOIN [dbo].[divisionXREF] x (NOLOCK) ON x.Division = c.comp_revtype
WHERE oh.ord_number = '113-889257'
AND x.AutoDivision IN ('+ @AutoDivision +')
AND lg.[lgh_outstatus] IN (''AVL'', ''PLN'', ''DSP'', ''STD'', ''PND'',''CMP'') '
EXEC(@cmd)
我建议在实现动态SQL解决方案之前阅读The Curse and Blessings of Dynamic SQL。
答案 1 :(得分:5)
为避免这种情况,您可以创建一个临时表,填写它,然后使用
IN (SELECT myField from #myTable)
答案 2 :(得分:3)
即使你连接看起来像几个不同的参数,你的IN子句实际上是将它作为一个单独的字符串进行测试(你确实将它声明为varchar),并且毫无疑问没有记录匹配该谓词。
看起来你正试图混合动态sql和标准查询。那不行。您的查询必须全部动态创建然后特别执行,或者您的IN子句必须使用可由子查询完成的单个参数进行输入。
您可以执行以下操作:
... AND x.AutoDivision IN
(SELECT Division WHERE Corp = 'GM') ...
OR
... AND x.AutoDivision IN
(SELECT 'Cad' UNION SELECT 'GMC' UNION SELECT 'Sat' UNION SELECT 'Che') ...
试试这个:
SELECT
oh.OrderNumber, lg.[lgh_number]
FROM
[dbo].[OrderHeader] oh (NOLOCK)
INNER JOIN
[dbo].[DistrctHeader] lg (NOLOCK) ON oh.[inv_number] = lg.[inv_number]
INNER JOIN
[dbo].[DealerCompany] c (NOLOCK) ON c.cmp_id = LEFT(oh.[ordernumber],3)
INNER JOIN
[dbo].[divisionXREF] x (NOLOCK) ON x.Division = c.comp_revtype
WHERE
oh.ord_number = '113-889257'
AND x.AutoDivision IN
(SELECT 'Cad' UNION SELECT 'GMC' UNION SELECT 'Sat' UNION SELECT 'Che')
AND lg.[lgh_outstatus] IN ('AVL', 'PLN', 'DSP', 'STD', 'PND','CMP')
这是一个内联子查询,UNION将任意字符串放入结果集中。 (带上一粒盐。我离Sql Server界面很远。)
答案 3 :(得分:1)
AND x.AutoDivision IN (@AutoDivision)
--AND x.AutoDivision IN ('Cad', 'Sat', 'GMC', 'Che')
你能否澄清这两行代码,他们是不是做同样的事情?
答案 4 :(得分:0)
CREATE FUNCTION [dbo].[Split]
(
@String NVARCHAR(4000),
@Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
'Data' = SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)
FROM Split
)
GO
DECLARE @AutoDivision varchar(50) = NULL
SET @AutoDivision ='Cad, Sat, GMC, Che'
SELECT * FROM divisionXREF P INNER JOIN dbo.SPLIT(ISNULL(@AutoDivision,''),',') as T ON P.lgh_outstatus = CASE T.strval WHEN '' THEN P.PG_CODE ELSE T.strval END