C # SQL Server - Meneruskan daftar ke prosedur tersimpan

112

Saya memanggil prosedur tersimpan SQL Server dari kode C # saya:

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();

Proc yang saya simpan cukup standar tetapi bergabung dengan QueryTable(karena itu kebutuhan untuk menggunakan proc yang disimpan).

Sekarang: Saya ingin menambahkan daftar string List<string>,, ke set parameter. Misalnya, kueri proc saya yang tersimpan berjalan seperti ini:

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

Namun, daftar stringnya dinamis dan panjangnya beberapa ratus.

Apakah ada cara untuk meneruskan daftar string List<string>ke proc yang disimpan ??? Atau apakah ada cara yang lebih baik untuk melakukan ini?

Terima kasih banyak, Brett

Brett
sumber
Kemungkinan, duplikat stackoverflow.com/questions/209686/…
Andrey Agibalov
Apa versi dari SQL Server ?? 2005 ?? 2008 ?? 2008 R2 ?? SQL Server 2008 dan yang lebih baru memiliki konsep "parameter nilai tabel" (lihat respons Redth untuk detailnya)
marc_s
Tip tidak terkait: SqlDataReader juga IDisposable jadi harus dalam usingblok.
Richardissimo

Jawaban:

179

Jika Anda menggunakan SQL Server 2008, ada fitur baru yang disebut Jenis Tabel Buatan Pengguna. Berikut ini contoh cara menggunakannya:

Buat Jenis Tabel Buatan Pengguna Anda:

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

Selanjutnya Anda perlu menggunakannya dengan benar dalam prosedur tersimpan Anda:

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

Akhirnya inilah beberapa sql untuk menggunakannya di c #:

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());
          }
         }
    }
}

Untuk menjalankan ini dari 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
Redth
sumber
10
Apakah itu harus mendefinisikan sebuah datatable untuk mengatur nilai parameter? Ada pendekatan ringan lainnya?
ca9163d9
2
Kami mencobanya tetapi kami menemukan kekurangannya karena tidak didukung oleh kerangka kerja Enitiy
Bishoy Hanna
7
HATI-HATI DENGAN SOLUSI INI JIKA ANDA MENGGUNAKAN LINQ2SQL, SEBAGAI TIDAK MENDUKUNG JENIS TABEL YANG DITETAPKAN PENGGUNA SEBAGAI PARAMETER !!! Solusi dapat ditemukan dalam jawaban Jon Raynor, menggunakan daftar yang dipisahkan koma dan fungsi parser, namun ini juga memiliki kekurangan ....
Fazi
3
@Fazi dalam kasus ini, jangan gunakan Linq2SQL. Lebih disukai daripada penggabungan string dan penguraian dalam T-SQL
Panagiotis Kanavos
2
Ya, jadi bagaimana Anda sebenarnya menjalankan ini dari SSMS?
Sinaesthetic
21

Pola tipikal dalam situasi ini adalah meneruskan elemen dalam daftar dipisahkan koma, dan kemudian dalam SQL membaginya menjadi tabel yang dapat Anda gunakan. Kebanyakan orang biasanya membuat fungsi khusus untuk melakukan ini seperti:

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

Dan kemudian Anda dapat menggunakannya di kueri lain.

Tejs
sumber
17
izinkan saya memasukkan tautan untuk implementasi dbo.SplitCommaString untuk kelengkapan: goo.gl/P9ROs
Veli Gebrev
3
Dan apa yang terjadi jika ada koma di salah satu bidang data Anda?
Kevin Panko
3
Batasi dengan pipa sebagai gantinya.
Alex In Paris
@AlexInParis Bagaimana jika ada pipa di salah satu bidang data Anda?
RayLoveless
2
Kemudian gunakan sesuatu yang tidak ada di bidang data Anda. Bersihkan data Anda, jika perlu tetapi tidak banyak data yang pernah saya lihat yang pernah menggunakan pipa. Jika mereka benar-benar diperlukan, temukan beberapa karakter lain seperti ¤ atau §.
Alex In Paris
9

Tidak, array / daftar tidak dapat diteruskan ke SQL Server secara langsung.

Pilihan berikut tersedia:

  1. Meneruskan daftar yang dipisahkan koma dan kemudian memiliki fungsi di SQL memisahkan daftar. Daftar yang dipisahkan koma kemungkinan besar akan diteruskan sebagai Nvarchar ()
  2. Lewati xml dan miliki fungsi di SQL Server untuk mengurai XML untuk setiap nilai dalam daftar
  3. Gunakan tipe tabel Buatan Pengguna yang ditentukan baru (SQL 2008)
  4. Buat SQL secara dinamis dan teruskan dalam daftar mentah sebagai "1,2,3,4" dan buat pernyataan SQL. Ini rentan terhadap serangan injeksi SQL, tetapi ini akan berhasil.
Jon Raynor
sumber
2

Ya, buat parameter proc Tersimpan sebagai VARCHAR(...) Dan kemudian berikan nilai yang dipisahkan koma ke prosedur tersimpan.

Jika Anda menggunakan Sql Server 2008 Anda dapat memanfaatkan TVP ( Parameter Nilai Tabel ): SQL 2008 TVP dan LINQ jika struktur QueryTable lebih kompleks daripada larik string jika tidak maka akan berlebihan karena memerlukan jenis tabel yang akan dibuat dalam SQl Server

sll
sumber
2

Buatlah sebuah datatable dengan satu kolom daripada List dan tambahkan string ke tabel. Anda dapat meneruskan datatable ini sebagai tipe terstruktur dan melakukan join lain dengan kolom judul pada tabel Anda.

lapar
sumber
itulah cara untuk pergi. Saya sebenarnya membuat tabel di sisi db dan dimuat dengan bcp write to server.
dier
0

Satu-satunya cara yang saya ketahui adalah membuat daftar CSV dan meneruskannya sebagai string. Kemudian, di sisi SP, pisahkan dan lakukan apa pun yang Anda butuhkan.

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

buat TYPE sebagai tabel dan beri nama sebagai "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

Buat prosedur seperti di atas dan beri nama sebagai "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();
                    }

di c #, Coba ini

Deepalakshmi
sumber