使用“IN”关键字和动态数据的SQL语法问题

时间:2010-12-15 21:21:21

标签: sql sql-server tsql sql-server-2000 subquery

我正在使用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')

我在这里缺少什么?

5 个答案:

答案 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

表值函数

A table valued function would allow you do what you want without using dynamic SQL -- there's more info in this article

答案 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