सी # एसक्यूएल सर्वर - एक सूची को एक संग्रहीत प्रक्रिया में पास करना


111

मैं अपने C # कोड से SQL सर्वर संग्रहीत कार्यविधि कह रहा हूं:

using (SqlConnection conn = new SqlConnection(connstring))
{
   conn.Open();
   using (SqlCommand cmd = new SqlCommand("InsertQuerySPROC", conn))
   {
      cmd.CommandType = CommandType.StoredProcedure;

      var STableParameter = cmd.Parameters.AddWithValue("@QueryTable", QueryTable);
      var NDistanceParameter = cmd.Parameters.AddWithValue("@NDistanceThreshold", NDistanceThreshold);
      var RDistanceParameter = cmd.Parameters.AddWithValue(@"RDistanceThreshold", RDistanceThreshold);

      STableParameter .SqlDbType = SqlDbType.Structured;
      NDistanceParameter.SqlDbType = SqlDbType.Int;
      RDistanceParameter.SqlDbType = SqlDbType.Int;

      // Execute the query
      SqlDataReader QueryReader = cmd.ExecuteReader();

मेरा संग्रहित खरीद काफी मानक है, लेकिन इसके साथ जुड़ता है QueryTable(इसलिए संग्रहीत खरीद के उपयोग की आवश्यकता है)।

अब: मैं List<string>पैरामीटर सेट पर, स्ट्रिंग्स की एक सूची जोड़ना चाहता हूं । उदाहरण के लिए, मेरी संग्रहीत खरीद क्वेरी इस प्रकार है:

SELECT feature 
FROM table1 t1 
INNER JOIN @QueryTable t2 ON t1.fid = t2.fid 
WHERE title IN <LIST_OF_STRINGS_GOES_HERE>

हालांकि, तार की सूची गतिशील और कुछ सौ लंबी है।

क्या List<string>संग्रहित खरीद के लिए तार की एक सूची पारित करने का एक तरीका है ??? या ऐसा करने का एक बेहतर तरीका है?

बहुत धन्यवाद, ब्रेट



SQL सर्वर का क्या संस्करण ?? 2005 ?? 2008 ?? 2008 R2 ?? SQL सर्वर 2008 और नए में "टेबल-वैल्यू-पैरामीटर्स" की अवधारणा है (विवरण के लिए रेड की प्रतिक्रिया देखें)
marc_s

असंबंधित टिप: SqlDataReader भी एक usingब्लॉक में होना चाहिए इसलिए आईडीआईसोपायरी है ।
रिचर्डिसिमो

जवाबों:


178

यदि आप SQL Server 2008 का उपयोग कर रहे हैं, तो एक नया फ़ीचर है जिसे यूज़र डिफ़ाइंड टेबल टाइप कहा जाता है। इसका उपयोग कैसे करें इसका एक उदाहरण इस प्रकार है:

अपना उपयोगकर्ता परिभाषित तालिका प्रकार बनाएं:

CREATE TYPE [dbo].[StringList] AS TABLE(
    [Item] [NVARCHAR](MAX) NULL
);

आगे आपको इसे अपनी संग्रहीत प्रक्रिया में ठीक से उपयोग करने की आवश्यकता है:

CREATE PROCEDURE [dbo].[sp_UseStringList]
    @list StringList READONLY
AS
BEGIN
    -- Just return the items we passed in
    SELECT l.Item FROM @list l;
END

अंत में यहाँ c # में इसका उपयोग करने के लिए कुछ sql है:

using (var con = new SqlConnection(connstring))
{
    con.Open();

    using (SqlCommand cmd = new SqlCommand("exec sp_UseStringList @list", con))
    {
        using (var table = new DataTable()) {
          table.Columns.Add("Item", typeof(string));

          for (int i = 0; i < 10; i++)
            table.Rows.Add("Item " + i.ToString());

          var pList = new SqlParameter("@list", SqlDbType.Structured);
          pList.TypeName = "dbo.StringList";
          pList.Value = table;

          cmd.Parameters.Add(pList);

          using (var dr = cmd.ExecuteReader())
          {
            while (dr.Read())
                Console.WriteLine(dr["Item"].ToString());
          }
         }
    }
}

SSMS से इसे निष्पादित करने के लिए

DECLARE @list AS StringList

INSERT INTO @list VALUES ('Apple')
INSERT INTO @list VALUES ('Banana')
INSERT INTO @list VALUES ('Orange')

-- Alternatively, you can populate @list with an INSERT-SELECT
INSERT INTO @list
   SELECT Name FROM Fruits

EXEC sp_UseStringList @list

10
क्या पैरामीटर के मान को सेट करने के लिए इसे एक डिटैटेबल को परिभाषित करना होगा? कोई अन्य प्रकाश दृष्टिकोण?
ca9163d9

2
हमने इसकी कोशिश की, लेकिन हमने पाया कि इसका दोष Enitiy फ्रेमवर्क द्वारा समर्थित नहीं है
हैना

7
इस समाधान के साथ यदि आप USIN LINQ2SQL के साथ हैं, तो यह अपरिचित लोगों के रूप में उपयोग किए जाने योग्य उपयोगों का समर्थन नहीं करता है !!! जॉन रेन्नोर के जवाब में एक कमबैक पाया जा सकता है, कॉमा से अलग की गई सूचियों और एक पार्सर फ़ंक्शन का उपयोग करते हुए, हालांकि इसमें कमियां भी हैं ....
Fazi

3
@ फ़ाज़ी इस मामले में, Linq2SQL का उपयोग न करें। यह टी-एसक्यूएल में स्ट्रिंग
संघनन

2
हाँ, तो आप वास्तव में SSMS से इसे कैसे निष्पादित करते हैं?
सिनास्टैटिक

21

इस स्थिति में विशिष्ट पैटर्न एक अल्पविराम सीमांकित सूची में तत्वों को पास करना है, और फिर SQL स्प्लिट में है कि एक तालिका में आप उपयोग कर सकते हैं। अधिकांश लोग आमतौर पर ऐसा करने के लिए एक निर्दिष्ट कार्य बनाते हैं:

 INSERT INTO <SomeTempTable>
 SELECT item FROM dbo.SplitCommaString(@myParameter)

और फिर आप इसे अन्य प्रश्नों में उपयोग कर सकते हैं।


17
मुझे एक dbo.SplitCommaString पूर्णता के लिए कार्यान्वयन के लिए एक कड़ी में फेंक दें: goo.gl/P9ROs
Veli Gebrev

3
और जब आपके किसी डेटा फ़ील्ड में अल्पविराम होता है तो क्या होता है?
केविन पैनको

3
इसके बजाय पाइप के साथ परिसीमन करें।
एलेक्स पेरिस में

@AlexInParis यदि आपके किसी डेटा फ़ील्ड में कोई पाइप है तो क्या होगा?
रेवेल्वेस

2
फिर कुछ का उपयोग करें जो आपके डेटा फ़ील्ड में नहीं है। अपने डेटा को साफ़ करें, यदि आवश्यक हो लेकिन इतना डेटा नहीं जो मैंने कभी देखा है कभी पाइप का इस्तेमाल किया है। यदि वे पूरी तरह से आवश्यक हैं तो कुछ अन्य चरित्र जैसे ¤ या some खोजें।
एलेक्स पेरिस में

9

नहीं, सरणियों / सूचियों को SQL सर्वर से सीधे पारित नहीं किया जा सकता है।

निम्न विकल्प उपलब्ध हैं:

  1. अल्पविराम-सीमांकित सूची को पास करना और फिर SQL में फ़ंक्शन करने से सूची विभाजित हो जाती है। अल्पविराम सीमांकित सूची को सबसे अधिक Nvarchar () के रूप में पारित किया जाएगा।
  2. Xml पास करें और सूची में प्रत्येक मान के लिए SQL सर्वर में XML को पार्स करें
  3. नए परिभाषित उपयोगकर्ता परिभाषित तालिका प्रकार (SQL 2008) का उपयोग करें
  4. डायनामिक रूप से एसक्यूएल का निर्माण करें और कच्ची सूची में "1,2,3,4" के रूप में पास करें और एसक्यूएल स्टेटमेंट का निर्माण करें। यह SQL इंजेक्शन हमलों के लिए प्रवण है, लेकिन यह काम करेगा।

2

हां, स्टोर्ड प्रोकस पैरामीटर बनाएं VARCHAR(...) और फिर कॉमा से अलग किए गए मानों को एक संग्रहीत प्रक्रिया में पास करें।

यदि आप Sql Server 2008 का उपयोग कर रहे हैं, तो आप TVP ( टेबल वैल्यू पैरामीटर्स ) का लाभ उठा सकते हैं : SQL 2008 TVP और LINQ यदि स्ट्रिंग की सरणी से अधिक जटिल QueryTable की संरचना है अन्यथा यह एक ओवरकिल होगा क्योंकि SQl सर्वर के भीतर तालिका प्रकार बनाने की आवश्यकता होती है


2

सूची के बजाय एक कॉलम के साथ एक डिटैटेबल बनाएं और तालिका में तार जोड़ें। आप इस डेटा प्रकार को संरचित प्रकार के रूप में पास कर सकते हैं और अपनी तालिका के शीर्षक क्षेत्र के साथ एक और कार्य कर सकते हैं।


जाने का रास्ता है। मैंने वास्तव में db साइड पर एक टेबल बनाया और सर्वर पर bcp लिखने के साथ लोड किया।
Dier

1

यदि आप SQL में CSV सूची को विभाजित करना पसंद करते हैं, तो कॉमन टेबल एक्सप्रेशंस (CTE) का उपयोग करने का एक अलग तरीका है । सीटीई का उपयोग करके स्ट्रिंग विभाजन का कुशल तरीका देखें ।


धन्यवाद। इसके बजाय एक ढेर अतिप्रवाह प्रश्न में बदल गया।
लैरी सिल्वरमैन

0

एकमात्र तरीका मुझे पता है कि CSV सूची का निर्माण कर रहा है और फिर इसे स्ट्रिंग के रूप में पारित कर रहा है। फिर, सपा की तरफ, बस इसे विभाजित करें और आपको जो कुछ भी ज़रूरत है उसे करें।


0
CREATE TYPE [dbo].[StringList1] AS TABLE(
[Item] [NVARCHAR](MAX) NULL,
[counts][nvarchar](20) NULL);

तालिका के रूप में एक TYPE बनाएं और इसे "StringList1" नाम दें

create PROCEDURE [dbo].[sp_UseStringList1]
@list StringList1 READONLY
AS
BEGIN
    -- Just return the items we passed in
    SELECT l.item,l.counts FROM @list l;
    SELECT l.item,l.counts into tempTable FROM @list l;
 End

ऊपर के रूप में एक प्रक्रिया बनाएँ और इसे "UserStringList1" के रूप में नाम दें

String strConnection = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString.ToString();
            SqlConnection con = new SqlConnection(strConnection);
            con.Open();
            var table = new DataTable();

            table.Columns.Add("Item", typeof(string));
            table.Columns.Add("count", typeof(string));

            for (int i = 0; i < 10; i++)
            {
                table.Rows.Add(i.ToString(), (i+i).ToString());

            }
                SqlCommand cmd = new SqlCommand("exec sp_UseStringList1 @list", con);


                    var pList = new SqlParameter("@list", SqlDbType.Structured);
                    pList.TypeName = "dbo.StringList1";
                    pList.Value = table;

                    cmd.Parameters.Add(pList);
                    string result = string.Empty;
                    string counts = string.Empty;
                    var dr = cmd.ExecuteReader();

                    while (dr.Read())
                    {
                        result += dr["Item"].ToString();
                        counts += dr["counts"].ToString();
                    }

सी # में, यह कोशिश करो

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