SQL - 使用IN子句的变量

时间:2009-12-22 18:43:09

标签: sql sql-server

我希望做以下事情:

declare @FrameNumber nvarchar(20)
set @FrameNumber = '(p1, p2)'

select from myTable where c1 in @FrameNumber

这个的正确语法是什么?

(注意:我需要将@FrameNumber的值作为参数传递给存储过程...所以我必须至少使用字符串“p1,p2”)

会预先确定和回答SQL 7兼容,但SQL 2005就足够了。

7 个答案:

答案 0 :(得分:9)

DECLARE @FrameNumbers TABLE (code NVARCHAR(20) PRIMARY KEY)

INSERT
INTO   @framenumbers
VALUES ('p1')

INSERT
INTO   @framenumbers
VALUES ('p2')

SELECT  *
FROM    mytable
WHERE   c1 IN
        (
        SELECT  code
        FROM    @framenumbers
        )

答案 1 :(得分:2)

CREATE FUNCTION [dbo].[func_ParseStringToTable] (@stringIN varchar(2000)) 
RETURNS @tOUT TABLE(RoomID int) AS
BEGIN
DECLARE @pos int
SET @pos=CHARINDEX(',',@StringIN)
WHILE @pos>0
     BEGIN
     INSERT @tOUT(RoomID) SELECT LEFT(@StringIN,CHARINDEX(',',@StringIN)-1)
     SET @stringIN = SUBSTRING(@StringIN,CHARINDEX(',',@StringIN)+1,LEN(@StringIN))
     SET @pos=CHARINDEX(',',@StringIN)
     END
IF LEN(@StringIN)>0
     BEGIN
     INSERT @tOUT(RoomID) SELECT @StringIN
     END
RETURN 
END

...使用

SELECT * FROM table WHERE id IN (func_ParseStringToTable(@ids))

答案 2 :(得分:1)

您可以将这些值加载到表变量中,也可以使用动态sql。以下是各自的例子:

TABLE VARIABLE

DECLARE @FrameNumbers TABLE (
    Frame NVARCHAR(20)
)

INSERT INTO @FrameNumbers (
    Frame
)
SELECT 'p1'
UNION ALL SELECT 'p2'

选项1:

SELECT * FROM myTable WHERE c1 in (
    SELECT Frame
    FROM @FrameNumbers
)

选项2:

SELECT
    m.*
FROM myTable m
INNER JOIN @FrameNumbers f ON f.Frame = m.c1

一切都很好,但这是我的最爱:

DYNAMIC SQL

DECLARE 
@FrameNumber nvarchar(20),
@sql nvarchar(max),
@ParamDef nvarchar(1000)

SET @FrameNumber = '(p1, p2)'

SET @sql = N'SELECT FROM myTable WHERE c1 IN ' + @FrameNumber

EXECUTE dbo.sp_ExecuteSQL @sql

答案 3 :(得分:1)

我有另一个解决方案,分裂功能,

DECLARE @FrameNumber NVARCHAR(20)
SET @FrameNumber = 'p1,p2'

SELECT * FROM MyTable WHERE ProductCode IN 
(SELECT Value FROM fn_Split(@FrameNumber, ','))

<强>输出:

enter image description here

拆分功能:

CREATE FUNCTION fn_Split (
    @String VARCHAR(8000)
    ,@Delimiter CHAR(1)
    )
RETURNS @temptable TABLE (Value VARCHAR(8000))
AS
BEGIN
    DECLARE @idx INT
    DECLARE @slice VARCHAR(8000)

    SELECT @idx = 1

    IF len(@String) < 1
        OR @String IS NULL
        RETURN

    WHILE @idx != 0
    BEGIN
        SET @idx = charindex(@Delimiter, @String)

        IF @idx != 0
            SET @slice = left(@String, @idx - 1)
        ELSE
            SET @slice = @String

        IF (len(@slice) > 0)
            INSERT INTO @temptable (Value)
            VALUES (@slice)

        SET @String = right(@String, len(@String) - @idx)

        IF len(@String) = 0
            BREAK
    END

    RETURN
END

答案 4 :(得分:0)

什么版本的SQL Server?

如果您在2008年,您可能可以使用表数据类型。简化了这些事情。

答案 5 :(得分:0)

如果您使用的是Sql Server 2005+,请查看此内容

--Split
DECLARE @textXML XML
DECLARE @data NVARCHAR(MAX), 
        @delimiter NVARCHAR(5)

SELECT  @data = 'A,B,C',
        @delimiter = ','

SELECT    @textXML = CAST('<d>' + REPLACE(@data, @delimiter, '</d><d>') + '</d>' AS XML)
SELECT  T.split.value('.', 'nvarchar(max)') AS data
FROM    @textXML.nodes('/d') T(split)

你可以在表格中选择。

查看XML Support in Microsoft SQL Server 2005

答案 6 :(得分:0)

最终解决方案:

DECLARE @FrameNumbers TABLE (FrameNumber NVARCHAR(20) PRIMARY KEY)

DECLARE @pos int
SET @pos=CHARINDEX(',',@FrameNumber)
WHILE @pos>0 BEGIN
     INSERT @FrameNumbers SELECT LEFT(@FrameNumber,CHARINDEX(',',@FrameNumber)-1)
     SET @FrameNumber = SUBSTRING(@FrameNumber,CHARINDEX(',',@FrameNumber)+1,LEN(@FrameNumber))
     SET @pos=CHARINDEX(',',@FrameNumber)
END
IF LEN(@FrameNumber)>0 BEGIN
     INSERT @FrameNumbers SELECT @FrameNumber
END

select from myTable where c1 in (select FrameNumber from @FrameNumbers)

感谢Quassnoi和Sam,这个解决方案只是您的解决方案的组合。