Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Chuyển từ điển sang thủ tục lưu trữ T-SQL

Câu trả lời được chấp nhận của việc sử dụng TVP nói chung là đúng, nhưng cần được làm rõ dựa trên lượng dữ liệu được truyền vào. Sử dụng DataTable là tốt (chưa kể là nhanh chóng và dễ dàng) cho các tập dữ liệu nhỏ hơn, nhưng đối với các tập lớn hơn thì không. không mở rộng quy mô vì nó sao chép tập dữ liệu bằng cách đặt nó vào DataTable đơn giản để chuyển nó đến SQL Server. Vì vậy, đối với các bộ dữ liệu lớn hơn, có một tùy chọn để truyền trực tuyến nội dung của bất kỳ bộ sưu tập tùy chỉnh nào. Yêu cầu thực sự duy nhất là bạn cần xác định cấu trúc theo kiểu SqlDb và lặp lại qua bộ sưu tập, cả hai đều là những bước khá đơn giản.

Tổng quan đơn giản về cấu trúc tối thiểu được hiển thị bên dưới, là sự điều chỉnh của câu trả lời mà tôi đã đăng trên Làm cách nào để chèn 10 triệu bản ghi trong thời gian ngắn nhất có thể ?, liên quan đến việc nhập dữ liệu từ một tệp và do đó hơi khác so với dữ liệu hiện không có trong bộ nhớ. Như bạn có thể thấy từ đoạn mã bên dưới, thiết lập này không quá phức tạp nhưng rất linh hoạt cũng như hiệu quả và có thể mở rộng.

Đối tượng SQL # 1:Xác định cấu trúc

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

Đối tượng SQL # 2:Sử dụng cấu trúc

-- 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

Mã C #, Phần 1:Xác định trình lặp / người gửi

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

Mã C #, Phần 2:Sử dụng trình lặp / người gửi

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. Định dạng số điện thoại trong SQL Server (T-SQL)

  2. Giải pháp cho cách đọc tệp nhật ký giao dịch SQL Server mà không có bất kỳ lỗi nào

  3. Chuyển đổi từ DateTime sang INT

  4. Làm cách nào để đặt thời gian chờ của tập lệnh SQL Server từ bên trong tập lệnh?

  5. Hoàn nguyên giao dịch Entity Framework 6