【问题标题】:SQL in (@Variable) query(@Variable) 查询中的 SQL
【发布时间】:2012-04-26 12:23:20
【问题描述】:

我有以下代码,问题是我的变量列表@LocationList 本质上是一个csv 字符串。当我将它用作 (@LocationList) 中的位置 ID 的一部分时,它说它不是一个 int (LocationID 是一个 int)。如何让这个 csv 字符串被 in 子句接受?

Declare @LocationList varchar(1000)
Set @LocationList = '1,32'

select Locations from table where Where LocationID in (@LocationList)

【问题讨论】:

标签: sql


【解决方案1】:

最有效的方法是使用动态 SQL,例如 rt2800 提及(Michael Allen 的注入警告)

但是你可以做一个函数:

ALTER  FUNCTION [dbo].[CSVStringsToTable_fn] ( @array VARCHAR(8000) )
RETURNS @Table TABLE ( value VARCHAR(100) )
AS 
    BEGIN
        DECLARE @separator_position INTEGER,
            @array_value VARCHAR(8000)  

        SET @array = @array + ','

        WHILE PATINDEX('%,%', @array) <> 0 
            BEGIN
                SELECT  @separator_position = PATINDEX('%,%', @array)
                SELECT  @array_value = LEFT(@array, @separator_position - 1)

                INSERT  @Table
                VALUES  ( @array_value )

                SELECT  @array = STUFF(@array, 1, @separator_position, '')
            END
        RETURN
    END

并从中选择:

DECLARE @LocationList VARCHAR(1000)
SET @LocationList = '1,32'

SELECT  Locations 
FROM    table
WHERE   LocationID IN ( SELECT   *
                           FROM     dbo.CSVStringsToTable_fn(@LocationList) )

SELECT  Locations
FROM    table loc
        INNER JOIN dbo.CSVStringsToTable_fn(@LocationList) list
            ON list.value = loc.LocationID

当您尝试将多值列表从 SSRS 发送到 PROC 时,这非常有用。

【讨论】:

  • 请注意,您可能需要根据需要进行投射
【解决方案2】:

我经常有这个要求,有时,如果你非常了解你要搜索的列[大小/格式/长度],你可以做一种正则表达式。

类似这样的:

  DECLARE @MyListOfLocation varchar(255)
  set @MyListOfLocation  = '|1|32|36|24|3|'

  Select LocationID 
  from  Table 
  where @MyListOfLocation like '%|' +  LocationID + '|%'

注意:PIPE 字符用于保护查询不返回任何包含单个字符(例如“1”)的 LocationID。

这是一个完整的工作示例:

DECLARE @MyListOfLocation varchar(255)
set @MyListOfLocation  = '|1|11|21|'

SELECT LocationName
FROM (
        select '1' as LocationID, 'My Location 1' as LocationName
        union all
        select '11' as LocationID, 'My Location 11' as LocationName
        union all
        select '12' as LocationID, 'My Location 12' as LocationName
        union all
        select '13' as LocationID, 'My Location 13' as LocationName
        union all
        select '21' as LocationID, 'My Location 21' as LocationName
    ) as MySub
where @MyListOfLocation like '%|' + LocationID + '|%'

警告!此方法对索引不友好!

如果您想在所有这些中添加一些 IN(@MyListOfLocation),以利用 INDEXES,您可以将脚本修改为:

SELECT MyDATA.* 
FROM   HugeTableWithAnIndexOnLocationID as MyDATA 
WHERE  LocationID in (
      Select LocationID 
      from  Table 
      where @MyListOfLocation like '%|' +  LocationID + '|%')

【讨论】:

    【解决方案3】:
    declare @querytext Nvarchar(MAX)
    
    set @querytext = 'select Locations from table where Where LocationID in (' + @LocationList + ');';
    
    exec sp_executesql @querytext;
    

    【讨论】:

    • 强烈建议不要使用这种方式,sql注入风险太大。一般远离exec方法,太危险了。
    • @MichaelAllen 这取决于您的列表是如何生成的,但是您对 SQL 注入是正确的,并且 sp_executesql 会更好 - 因为它甚至可以缓存执行计划。
    猜你喜欢
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    相关资源
    最近更新 更多