Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Lulus Kamus ke Prosedur Tersimpan T-SQL

Jawaban yang diterima dari menggunakan TVP umumnya benar, tetapi perlu beberapa klarifikasi berdasarkan jumlah data yang dikirimkan. Menggunakan DataTable baik-baik saja (belum lagi cepat dan mudah) untuk kumpulan data yang lebih kecil, tetapi untuk kumpulan yang lebih besar memang demikian tidak skala mengingat bahwa itu menduplikasi dataset dengan menempatkannya di DataTable hanya untuk cara meneruskannya ke SQL Server. Jadi, untuk kumpulan data yang lebih besar, ada opsi untuk mengalirkan konten koleksi kustom apa pun. Satu-satunya persyaratan yang sebenarnya adalah Anda perlu mendefinisikan struktur dalam hal tipe SqlDb dan beralih melalui koleksi, yang keduanya merupakan langkah yang cukup sepele.

Gambaran sederhana dari struktur minimal ditunjukkan di bawah ini, yang merupakan adaptasi dari jawaban yang saya posting di Bagaimana saya bisa memasukkan 10 juta catatan dalam waktu sesingkat mungkin?, yang berkaitan dengan mengimpor data dari file dan karenanya sedikit berbeda sebagai data saat ini tidak ada dalam memori. Seperti yang Anda lihat dari kode di bawah, pengaturan ini tidak terlalu rumit namun sangat fleksibel serta efisien dan skalabel.

Objek SQL # 1:Tentukan strukturnya

-- First: You need a User-Defined Table Type
CREATE TYPE dbo.IDsAndOrderNumbers AS TABLE
(
   ID NVARCHAR(4000) NOT NULL,
   SortOrderNumber INT NOT NULL
);
GO

Objek SQL # 2:Gunakan struktur

-- Second: Use the UDTT as an input param to an import proc.
--         Hence "Tabled-Valued Parameter" (TVP)
CREATE PROCEDURE dbo.ImportData (
   @ImportTable    dbo.IDsAndOrderNumbers READONLY
)
AS
SET NOCOUNT ON;

-- maybe clear out the table first?
TRUNCATE TABLE SchemaName.TableName;

INSERT INTO SchemaName.TableName (ID, SortOrderNumber)
    SELECT  tmp.ID,
            tmp.SortOrderNumber
    FROM    @ImportTable tmp;

-- OR --

some other T-SQL

-- optional return data
SELECT @NumUpdates AS [RowsUpdated],
       @NumInserts AS [RowsInserted];
GO

Kode C#, Bagian 1:Tentukan iterator/pengirim

using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using Microsoft.SqlServer.Server;

private static IEnumerable<SqlDataRecord> SendRows(Dictionary<string,int> RowData)
{
   SqlMetaData[] _TvpSchema = new SqlMetaData[] {
      new SqlMetaData("ID", SqlDbType.NVarChar, 4000),
      new SqlMetaData("SortOrderNumber", SqlDbType.Int)
   };
   SqlDataRecord _DataRecord = new SqlDataRecord(_TvpSchema);
   StreamReader _FileReader = null;

      // read a row, send a row
      foreach (KeyValuePair<string,int> _CurrentRow in RowData)
      {
         // You shouldn't need to call "_DataRecord = new SqlDataRecord" as
         // SQL Server already received the row when "yield return" was called.
         // Unlike BCP and BULK INSERT, you have the option here to create an
         // object, do manipulation(s) / validation(s) on the object, then pass
         // the object to the DB or discard via "continue" if invalid.
         _DataRecord.SetString(0, _CurrentRow.ID);
         _DataRecord.SetInt32(1, _CurrentRow.sortOrderNumber);

         yield return _DataRecord;
      }
}

Kode C#, Bagian 2:Gunakan iterator/pengirim

public static void LoadData(Dictionary<string,int> MyCollection)
{
   SqlConnection _Connection = new SqlConnection("{connection string}");
   SqlCommand _Command = new SqlCommand("ImportData", _Connection);
   SqlDataReader _Reader = null; // only needed if getting data back from proc call

   SqlParameter _TVParam = new SqlParameter();
   _TVParam.ParameterName = "@ImportTable";
// _TVParam.TypeName = "IDsAndOrderNumbers"; //optional for CommandType.StoredProcedure
   _TVParam.SqlDbType = SqlDbType.Structured;
   _TVParam.Value = SendRows(MyCollection); // method return value is streamed data
   _Command.Parameters.Add(_TVParam);
   _Command.CommandType = CommandType.StoredProcedure;

   try
   {
      _Connection.Open();

      // Either send the data and move on with life:
      _Command.ExecuteNonQuery();
      // OR, to get data back from a SELECT or OUTPUT clause:
      SqlDataReader _Reader = _Command.ExecuteReader();
      {
       Do something with _Reader: If using INSERT or MERGE in the Stored Proc, use an
       OUTPUT clause to return INSERTED.[RowNum], INSERTED.[ID] (where [RowNum] is an
       IDENTITY), then fill a new Dictionary<string, int>(ID, RowNumber) from
       _Reader.GetString(0) and _Reader.GetInt32(1). Return that instead of void.
      }
   }
   finally
   {
      _Reader.Dispose(); // optional; needed if getting data back from proc call
      _Command.Dispose();
      _Connection.Dispose();
   }
}


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server 2005 Menggunakan DateAdd untuk menambahkan hari ke tanggal

  2. Memodifikasi Pekerjaan Agen SQL Server (T-SQL)

  3. Bagaimana cara memeriksa hasil pekerjaan paket SSIS setelah menyelesaikan eksekusinya?

  4. Kapan menggunakan Common Table Expression (CTE)

  5. Bagaimana cara mengubah nilai kolom identitas secara terprogram?