【问题标题】:Attempting to use a subquery as an expression, need alternatives / help尝试使用子查询作为表达式,需要替代方案/帮助
【发布时间】:2011-07-05 14:31:07
【问题描述】:

SQL Server 2005。

我有一个存储过程,它接受一些参数,这些参数实际上可能有也可能没有传递给它们的数据。因此,它们可能以空字符串的形式出现,也可能带有数据。

数据将是一个分隔的 ID 列表...制造商 ID、目录 ID 等。proc 搜索记录,如果这些参数中的任何一个有数据,则在 where 子句中使用它。

仅供参考:Split 是一个拆分字符串(接受分隔符)并返回表格的函数。


WHERE

...

AND m.Mfg_ID in (CASE WHEN @manufacturerIds <> '' THEN (SELECT * FROM Split(@manufacturerIds, '|')) ELSE (select m.Mfg_Id) END)

我收到以下错误: “子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。”

我不明白的是,如果我删除 CASE 语句,那么我就只有这个......


WHERE

...

AND m.Mfg_ID in (SELECT * FROM Split(@manufacturerIds, '|'))

...运行正常;但是,这使我无法传递空字符串。

任何帮助将不胜感激!

【问题讨论】:

    标签: sql-server-2005 tsql subquery expression


    【解决方案1】:

    区别在于(select m.Mfg_Id)返回单行,而(select * from split(...))返回多行。 case 返回单个值,因此它不知道如何处理来自 Split 的多行。

    您可以将它们联合在一起,而不是 case

    and m.Mfg_ID in 
    (
    select  *
    from    Split(@manufacturerIds, '|')
    where   @manufacturerIds <> ''
    union all
    select  m.Mfg_Id
    where   @manufacturerIds = ''
    )
    

    union 的下半部分仅在@manufacturerIds = '' 时运行。

    【讨论】:

      【解决方案2】:
      SELECT m.Mfg_ID -- , other columns
          FROM dbo.base_table_name AS m
          LEFT OUTER JOIN dbo.Split(@ManufacturerIds) AS f
          ON (m.Mfg_id = f.column_name)
          WHERE @manufacturerIds = '' 
          OR f.column_name IS NOT NULL;
      

      【讨论】:

      • 考虑这个 SET @manufacturerIds = '1|1|'。我认为你应该使用存在而不是加入。我想它也可以加快 sql,因为您可以先检查 @manufacturerIds = ''
      【解决方案3】:

      我认为这可能与 CASE 子查询的“SELECT *”部分有关。尝试只选择一列。

      【讨论】:

        【解决方案4】:

        我已尝试将您的“where”子句重写为对我来说更合乎逻辑的内容。我没有将文本分成更小的部分,而是将文本与“LIKE”进行比较。我认为这会带来更好的性能。

        DECLARE @t table (Mfg_id VARCHAR(10))
        DECLARE @manufacturerIds VARCHAR(50)
        INSERT @t 
        SELECT 'aaa' UNION ALL SELECT 'a' UNION ALL SELECT 'ab' UNION ALL SELECT 'abc'
        
        SET @manufacturerIds = '|' +'aaa|abc|bbb' + '|'
        
        SELECT Mfg_ID matching FROM @t m
        WHERE ( @manufacturerIds like '%|' + CAST(m.Mfg_ID AS VARCHAR(20)) + '|%' OR @manufacturerIds = '')
        

        结果:

        matching
        ----------
        aaa
        abc
        

        如果您只想在此处更正您的当前脚本,您可以这样做:

        AND (@manufacturerIds = '' or m.Mfg_ID in (SELECT * FROM Split(@manufacturerIds, '|')))
        

        【讨论】:

        • 如果 Mfg_ID 是数字数据类型,这可能会导致性能问题,实际上会导致当前写入的错误 (Msg 245)。
        • 我已经将变量声明为 varchar,但如果它是非常可能的数字,它确实会失败。更改了脚本以允许使用数字。分裂真的会更快吗?
        • 在我的测试中,是的,但它实际上取决于 (a) 变量确实有变量时列表的长度,(b) 表格的内容,以及 (c) 列表实际出现的频率一个空字符串。请参阅我的答案,了解我认为更直接的方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-27
        • 1970-01-01
        • 1970-01-01
        • 2013-10-17
        相关资源
        最近更新 更多