Where IN değerlerini bir değişkende saklamak

değişebilir içinde virgülle ayrılmış bir liste saklamak ve bu verileri bu şekilde kullanmak istiyorum iş gibi görünmüyor.Aşağıdaki hatayı döndürür:

Nvarchar değeri '2, 4, 7, 9' değerine dönüştürülürken dönüştürme başarısız oldu   veri türü smallint.

Aşağıdaki sorgusunu yazdım:

declare @sch nvarchar(255)
set @sch = '2, 4, 7, 9'

SELECT *
FROM stu
WHERE sc IN (@sch);

Teşekkür ederim.

0
Temel olarak, sadece bir IN yan tümcesini parametrelemek istiyorsunuz.
katma yazar Andriy M, kaynak

6 cevap

StackOverflow'ta başka bir yayında bazı bilgiler buldum burada Bu, bunun nasıl yapılacağına dair iyi bir örnek olduğunu düşündüğüm şeyi verdi. Minimum miktarda kod vardır ve ayrıca SQL'i (istemedim) bir değişkende saklamaz. CONVERT (varchar (max), SC) bir değişkende saklanırsa daha az kod olabileceğini düşünüyorum ... ancak WHERE yan tümcesinin bir parçası olarak bunu nasıl yapacağınızdan emin değilim.

declare @sch nvarchar(255)
set @sch = '2, 4 , 7,9,' -- can have spaces or not, or comma at end.
set @sch = REPLACE(@sch,' ','') -- strips out any spaces

SELECT * FROM stu
WHERE @sch LIKE '%,'+CONVERT(varchar(max),SC)+',%'
    OR @sch LIKE '%,'+CONVERT(varchar(max),SC)
    OR @sch LIKE CONVERT(varchar(max),SC)+',%'
    OR @sch=CONVERT(varchar(max),SC);
1
katma

@ user3513237 Aşağıdaki kodu kullanın

declare @sch nvarchar(255)
declare @sch1 nvarchar(255)
declare @records table(a int)
declare @lenSch int
declare @i int =1
set @sch = '2,4,7,9'
print @sch
set @lenSch=(select len(@sch))
while(@i<[email protected])
begin
insert  into @records
select SUBSTRING(@sch,@i,1)
set @[email protected]+2
end
SELECT *
FROM stu
WHERE sc IN (select a from @records)
0
katma

Mümkün olduğunda, SQL bunlar için optimize edilmediğinden imleçleri veya döngüleri kullanmaktan kaçınmak istersiniz. İşte özyinelemeli bir çözüm.

Değişkenleriniz

DECLARE @stu TABLE (col1 INT);
INSERT INTO @stu VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);

DECLARE @sch nvarchar(255);
SET @sch = '2,4,7,9';
SET @sch = REPLACE(@sch,' ','') + ','; -- Put the end comma there instead of having to use a case statement in my query
                                       -- As well as getting rid of useless white space with REPLACE()

Gerçek Sorgu

WITH CTE
AS
(
    SELECT 1 row_count, CAST(SUBSTRING(@sch,0,CHARINDEX(N',',@sch,0)) AS NVARCHAR(255)) AS search_val, CHARINDEX(',',@sch,0) + 1 AS starting_position
    UNION ALL
    SELECT row_count + 1,CAST(SUBSTRING(@sch,starting_position,CHARINDEX(',',@sch,starting_position) - starting_position) AS NVARCHAR(255)) AS search_val, CHARINDEX(',',@sch,starting_position) + 1 AS starting_position
    FROM CTE
    WHERE row_count < (LEN(@sch) - LEN(REPLACE(@sch,',','')))
)

SELECT *
FROM @stu
WHERE col1 IN (SELECT CAST(search_val AS INT) FROM CTE)

Sonuçlar:

col1
-----------
2
4
7
9
0
katma

Dizeyi bölmek için aşağıdaki işlevi kullanabilirsiniz ve bundan sonra bu işlevi aşağıdaki gibi sorgulayabilirsiniz:

CREATE FUNCTION [dbo].[SDF_SplitString]
(
@sString nvarchar(2048),
@cDelimiter nchar(1)
)
RETURNS @tParts TABLE ( part nvarchar(2048) )
AS
BEGIN
if @sString is null return
declare @iStart int,
        @iPos int
if substring( @sString, 1, 1 ) = @cDelimiter 
begin
    set @iStart = 2
    insert into @tParts
    values( null )
end
else 
    set @iStart = 1
while 1=1
begin
    set @iPos = charindex( @cDelimiter, @sString, @iStart )
    if @iPos = 0
        set @iPos = len( @sString )+1
    if @iPos - @iStart > 0          
        insert into @tParts
        values  ( substring( @sString, @iStart, @[email protected] ))
    else
        insert into @tParts
        values( null )
    set @iStart = @iPos+1
    if @iStart > len( @sString ) 
        break
end
RETURN
END

Bu işlevi veritabanınıza ekledikten sonra sorgunuzu aşağıdaki gibi çalıştırın:

DECLARE @sch NVARCHAR(255)
SET @sch = '2, 4, 7, 9'

SELECT  *
        FROM    stu
        WHERE   sc IN ( SELECT  part
                                FROM    dbo.SDF_SplitString(@sch, ',') );
0
katma

Bu sorguyu kullan:

declare @sch nvarchar(255)
set @sch = '2, 4, 7, 9'

declare @query varchar(4000)= 
'
SELECT *
FROM 
(
    select 2 as sc
    union all
    select 1 as sc
    union all
    select 7 as sc
) as stu
WHERE sc IN ('[email protected]+');'

exec (@query)

Sadece alt sorguyu gerçek tabloya çevir

0
katma
İşe yarayacak, ancak böyle dinamik sql kullanılması tavsiye edilmez. Bir nedenden ötürü sql enjeksiyon saldırılarına karşı en savunmasız olanıdır. Eğer sch değeri '1,2,4,7,9) veya (1 = 1' ise ne olacağını hayal edin.
katma yazar Zohar Peled, kaynak
@VladimirSemashkin: Cevabımı okursanız, özellikle bir dizgeyi sql'ye bölmenin her zaman en iyi seçenek olmadığını ve sql'e bir parametre listesini geçirmenin daha iyi yollar olduğunu söylediğimi göreceksiniz. Önerinizin bu gibi durumlar için iyi bir çözüm olduğu konusunda hemfikir değilim, çünkü durum OP’nin yazdığı gibi değil. eğer öyleyse doğru cevap SELECT * stu WHERE sc IN (2,4,7,9); Muhtemelen bir değer listesinin saklı bir işleme nasıl geçirileceği ile ilgili bir soru ve bunun için dinamik sql'den daha iyi yollar var.
katma yazar Zohar Peled, kaynak
Bu böyle bir durum için iyi bir yoldur. İpinizi bölmeyi denerseniz çok daha fazla kaynak harcarsınız. Dinamik sql - çok kullanışlı ama onu kullanırken düşünmeniz gerekir. Bu durum onu ​​kullanmak için iyi bir nedendir.
katma yazar Vladimir Semashkin, kaynak
Sorguyu örneğiniz gibi bir değişkende saklamamayı tercih ederim. Belki bunu yapmanın başka bir yolu vardır?
katma yazar user3513237, kaynak

Sorununuzu çözecek sorgu burada:

declare @sch nvarchar(255);
declare @query varchar(200);
set @sch = '2, 4, 7, 9';
set @query = 'select * from stu where sc in (' + @sch + ')';
--print @query;
exec(@query);
0
katma