परिचालक के साथ उपयोग करने के लिए चर को परिभाषित करें (T-SQL)


138

मेरे पास Transact-SQL क्वेरी है जो IN ऑपरेटर का उपयोग करता है। कुछ इस तरह:

select * from myTable where myColumn in (1,2,3,4)

क्या संपूर्ण सूची "(1,2,3,4)" को रखने के लिए एक चर को परिभाषित करने का एक तरीका है? मुझे इसे कैसे परिभाषित करना चाहिए?

declare @myList {data type}
set @myList = (1,2,3,4)
select * from myTable where myColumn in @myList

7
यह सवाल "Parameterize a SQL IN clause" सवाल जैसा नहीं है। यह प्रश्न देशी T-SQL को संदर्भित करता है, अन्य प्रश्न C # को संदर्भित करता है।
Slogmeister Extraordinaire

जवाबों:


113
DECLARE @MyList TABLE (Value INT)
INSERT INTO @MyList VALUES (1)
INSERT INTO @MyList VALUES (2)
INSERT INTO @MyList VALUES (3)
INSERT INTO @MyList VALUES (4)

SELECT *
FROM MyTable
WHERE MyColumn IN (SELECT Value FROM @MyList)

47
DECLARE @mylist TABLE (Id int)
INSERT INTO @mylist
SELECT id FROM (VALUES (1),(2),(3),(4),(5)) AS tbl(id)

SELECT * FROM Mytable WHERE theColumn IN (select id from @mylist)

टी-एसक्यूएल कहता है[Err] 42000 - [SQL Server]Must declare the scalar variable "@mylist".
Cees टिम्मरमैन

1
इसे आपके लिए निर्धारित किया गया है @Paul
स्टीफन जेड

5
क्या आप (VALUES (1),(2),(3),(4),(5))सीधे इस्तेमाल कर सकते हैं ?
toddmo

यह मेरी जरूरतों का सबसे अच्छा समाधान था। मुझे Ids की एक सूची के रूप में एक चर की आवश्यकता थी जो मुझे एक Select से मिल रही थी, इसलिए मान पूर्व निर्धारित नहीं थे। यह वही है जो मुझे चाहिए था। धन्यवाद!
Lexi847942

12

TSQL प्रश्नों के लिए गतिशील csv सूचियों से निपटने के दो तरीके हैं:

1) एक आंतरिक चयन का उपयोग करना

SELECT * FROM myTable WHERE myColumn in (SELECT id FROM myIdTable WHERE id > 10)

2) गतिशील रूप से सुव्यवस्थित TSQL का उपयोग करना

DECLARE @sql varchar(max)  
declare @list varchar(256)  
select @list = '1,2,3'  
SELECT @sql = 'SELECT * FROM myTable WHERE myColumn in (' + @list + ')'

exec sp_executeSQL @sql

3) एक संभावित तीसरा विकल्प तालिका चर है। यदि आपके पास SQl सर्वर 2005 है, तो आप तालिका चर का उपयोग कर सकते हैं। यदि आपका Sql Server 2008 पर आप संग्रहीत प्रक्रियाओं के लिए एक पैरामीटर के रूप में पूरे टेबल चर भी पास कर सकते हैं और इसे एक खंड में या सम्मिलित में खंड के रूप में उपयोग कर सकते हैं।

DECLARE @list TABLE (Id INT)

INSERT INTO @list(Id)
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4


SELECT
    * 
FROM 
    myTable
    JOIN @list l ON myTable.myColumn = l.Id

SELECT
    * 
FROM 
    myTable
WHERE
    myColumn IN (SELECT Id FROM @list)

5
@ badbod99 - यह एक सामान्यीकरण है और सभी सामान्यीकरण गलत हैं :) मैंने विकल्प की पेशकश की है
होलीस्टाईल

1
@Vilx - क्या आप चर @ की सेटिंग के लिए हैं? यदि ऐसा सेट ठीक है, लेकिन केवल एक चर सेट करता है, तो चयन के साथ आप एक बयान में कई चर को पॉप्युलेट कर सकते हैं। जैसा कि उनके बीच बहुत कुछ नहीं है, मैं हमेशा SELECT का उपयोग करने की आदत में हूँ।
होलीस्टाईल 11

1
सच ... बहुत सामान्य। आपका विकल्प बेहतर है। मेरा वास्तव में मतलब है कि एसक्यूएल स्क्रिप्ट के भीतर से एसक्यूएल उत्पन्न करना आमतौर पर अचूक कोड, इंजेक्शन के हमले का जोखिम और अन्य कुरूपता का एक कारण बनता है।
badbod99 11

9

इस तरह एक समारोह का उपयोग करें:

CREATE function [dbo].[list_to_table] (@list varchar(4000))
returns @tab table (item varchar(100))
begin

if CHARINDEX(',',@list) = 0 or CHARINDEX(',',@list) is null
begin
    insert into @tab (item) values (@list);
    return;
end


declare @c_pos int;
declare @n_pos int;
declare @l_pos int;

set @c_pos = 0;
set @n_pos = CHARINDEX(',',@list,@c_pos);

while @n_pos > 0
begin
    insert into @tab (item) values (SUBSTRING(@list,@c_pos+1,@n_pos - @c_pos-1));
    set @c_pos = @n_pos;
    set @l_pos = @n_pos;
    set @n_pos = CHARINDEX(',',@list,@c_pos+1);
end;

insert into @tab (item) values (SUBSTRING(@list,@l_pos+1,4000));

return;
end;

जैसे उपयोग करने के बजाय, आप फ़ंक्शन द्वारा दी गई तालिका के साथ एक आंतरिक जुड़ाव बनाते हैं:

select * from table_1 where id in ('a','b','c')

हो जाता है

select * from table_1 a inner join [dbo].[list_to_table] ('a,b,c') b on (a.id = b.item)

एक unindexed 1M रिकॉर्ड तालिका में दूसरे संस्करण में लगभग आधा समय लगा ...

चियर्स


5
DECLARE @myList TABLE (Id BIGINT) INSERT INTO @myList(Id) VALUES (1),(2),(3),(4);
select * from myTable where myColumn in(select Id from @myList)

कृपया ध्यान दें कि लंबी सूची या उत्पादन प्रणालियों के लिए इस तरह से उपयोग करने की अनुशंसा नहीं की जाती है क्योंकि यह साधारण INऑपरेटर की तुलना में बहुत अधिक धीमी हो सकती है जैसे someColumnName in (1,2,3,4)(8000+ आइटम सूची का उपयोग करके परीक्षण किया गया)


4

नहीं, ऐसा कोई प्रकार नहीं है। लेकिन कुछ विकल्प हैं:

  • गतिशील रूप से उत्पन्न क्वेरी (sp_executesql)
  • अस्थायी टेबल
  • टेबल-प्रकार चर (निकटतम वस्तु जो सूची में है)
  • XML स्ट्रिंग बनाएं और फिर इसे XML फ़ंक्शन (वास्तव में अजीब और गोल-गोल, तब तक तालिका में बदलें, जब तक कि आपके पास शुरू करने के लिए XML न हो)

इनमें से कोई भी वास्तव में सुरुचिपूर्ण नहीं हैं, लेकिन यह सबसे अच्छा है।


4

@ ल्यूक पर मामूली सुधार, "INSERT INTO" को दोहराने की आवश्यकता नहीं है: और @ realPT का उत्तर - चयन करने की आवश्यकता नहीं है:

DECLARE @MyList TABLE (Value INT) 
INSERT INTO @MyList VALUES (1),(2),(3),(4)

SELECT * FROM MyTable
WHERE MyColumn IN (SELECT Value FROM @MyList)

4

मुझे पता है कि यह अब पुराना है लेकिन TSQL => 2016, आप STRING_SPLIT का उपयोग कर सकते हैं:

DECLARE @InList varchar(255) = 'This;Is;My;List';

WITH InList (Item) AS (
    SELECT value FROM STRING_SPLIT(@InList, ';')
)

SELECT * 
FROM [Table]
WHERE [Item] IN (SELECT Tag FROM InList)


2

यदि आप दूसरी तालिका का उपयोग किए बिना ऐसा करना चाहते हैं, तो आप एक कास्ट के साथ एक LIKE तुलना कर सकते हैं:

DECLARE @myList varchar(15)
SET @myList = ',1,2,3,4,'

SELECT *
FROM myTable
WHERE @myList LIKE '%,' + CAST(myColumn AS varchar(15)) + ',%'

यदि आप जिस क्षेत्र की तुलना कर रहे हैं, वह पहले से ही एक स्ट्रिंग है तो आपको CAST की आवश्यकता नहीं होगी।

दोनों कॉलम मैच के आसपास और कॉमा में प्रत्येक अद्वितीय मूल्य एक सटीक मैच सुनिश्चित करेंगे। अन्यथा, 1 का मान '4,2,15,' वाली सूची में पाया जाएगा


1

जैसा कि पहले किसी ने भी इसका उल्लेख नहीं किया, Sql Server 2016 से शुरू होकर आप json सरण का उपयोग कर सकते हैं और OPENJSON (Transact-SQL):

declare @filter nvarchar(max) = '[1,2]'

select *
from dbo.Test as t
where
    exists (select * from openjson(@filter) as tt where tt.[value] = t.id)

आप इसमें परीक्षा दे सकते हैं sql fiddle demo

आप अधिक जटिल मामलों को भी आसान बना सकते हैं - मानों की खोज सूची और SQL में चर का उपयोग करके देखें जिसमें SQL चर के साथ खंड में है?


1

यह एक PATINDEX का उपयोग आईडी से एक गैर-अंक सीमांकित पूर्णांक सूची में आईडी से मिलान करने के लिए करता है।

-- Given a string @myList containing character delimited integers 
-- (supports any non digit delimiter)
DECLARE @myList VARCHAR(MAX) = '1,2,3,4,42'

SELECT * FROM [MyTable]
    WHERE 
        -- When the Id is at the leftmost position 
        -- (nothing to its left and anything to its right after a non digit char) 
        PATINDEX(CAST([Id] AS VARCHAR)+'[^0-9]%', @myList)>0 
        OR
        -- When the Id is at the rightmost position
        -- (anything to its left before a non digit char and nothing to its right) 
        PATINDEX('%[^0-9]'+CAST([Id] AS VARCHAR), @myList)>0
        OR
        -- When the Id is between two delimiters 
        -- (anything to its left and right after two non digit chars)
        PATINDEX('%[^0-9]'+CAST([Id] AS VARCHAR)+'[^0-9]%', @myList)>0
        OR
        -- When the Id is equal to the list
        -- (if there is only one Id in the list)
        CAST([Id] AS VARCHAR)=@myList

टिप्पणियाँ:

  • जब varchar के रूप में कास्टिंग और कोष्ठक में बाइट आकार निर्दिष्ट नहीं डिफ़ॉल्ट लंबाई 30 है
  • % (वाइल्डकार्ड) शून्य या अधिक वर्णों के किसी भी तार से मेल खाएगा
  • ^ (वाइल्डकार्ड) मैच के लिए नहीं
  • [^ 0-9] किसी भी गैर अंक चरित्र से मेल खाएगा
  • PATINDEX एक SQL मानक फ़ंक्शन है जो एक स्ट्रिंग में एक पैटर्न की स्थिति देता है


0

मुझे लगता है कि आपको एक स्ट्रिंग घोषित करनी होगी और फिर उस एसक्यूएल स्ट्रिंग को निष्पादित करना होगा।

Sp_executeSQL पर एक नजर डालें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.