it-swarm.com.de

Übergeben Sie datatable als Parameter in PostgreSQL

Ich habe eine Datentabelle in asp.net C #. Und ich möchte diese Datentabelle an die PostgreSQL-Funktion als Tabellenparameter übergeben. Wie ist es möglich?

Das folgende Beispiel ist dasselbe, befindet sich jedoch in SQL Server. Ich brauche das Gleiche, aber das Problem ist, dass ich PostgreSQL als Back-End habe, nicht SQL Server.

Einführung

Gespeicherte SQL Server-Prozeduren unterstützen System.Data.DataTable als Parameter. Wir können die Datentabelle mit ADO.Net auf die gleiche Weise an die gespeicherte Prozedur übergeben, wie wir sie mit der System.Data.SqlParameter-Klasse bereitgestellt haben, benötigen jedoch einige Änderungen am Datentyp. Normalerweise stellen wir DbType von SqlParameter für einen normalen Parameter wie varchar, nvarchar, int usw. wie im folgenden Code bereit.

SqlParameter sqlParam= new SqlParameter();  
sqlParam.ParameterName = "@StudentName";  
sqlParam.DbType = DbType.String;  
sqlParam.Value = StudentName;  

Im Fall eines Tabellenparameters müssen wir jedoch keinen DbType als Parameterdatentyp angeben. Wir müssen SqlType anstelle von DbType bereitstellen.

Beispiel

SqlParameter Parameter = new SqlParameter;  
Parameter.ParameterName = "@PhoneBook";  
Parameter.SqlDbType = SqlDbType.Structured;  
Parameter.Value = PhoneTable;  

Im folgenden Beispiel wird eine Liste von Telefonbüchern empfangen und mithilfe von ADO.Net in einer Datenbank gespeichert. In diesem Beispiel werden die Telefonbuchdetails aus der Liste abgerufen, in der Datentabelle gespeichert und diese Tabelle als Parameter an die gespeicherte Prozedur mit dem Namen NewPhoneBook übergeben.

//Phone book list    
List<PhoneBook> PhoneBooks    
 //CReating Table    
 DataTable PhoneTable = new DataTable();    

 // Adding Columns    
 DataColumn COLUMN=new DataColumn();    
 COLUMN.ColumnName="ID";    
 COLUMN.DataType= typeof(int);    
 PhoneTable.Columns.Add(COLUMN);    

 COLUMN = new DataColumn();    
 COLUMN.ColumnName = "ContactNumber";    
 COLUMN.DataType = typeof(string);    
 PhoneTable.Columns.Add(COLUMN);    

 COLUMN = new DataColumn();    
 COLUMN.ColumnName = "ContactName";    
 COLUMN.DataType = typeof(string);    
 PhoneTable.Columns.Add(COLUMN);    

 // INSERTING DATA    
 foreach (UserPhoneBook UPB in PhoneBooks)    
 {    
    DataRow DR = PhoneTable.NewRow();    
    DR[0] = UPB.UserName;    
    DR[1] = UPB.ContactNumber;    
    DR[2] = UPB.ContactName;    
    PhoneTable.Rows.Add(DR);    
 }    
 //Parameter declaration    
 SqlParameter[] Parameter = new SqlParameter[2];    
 Parameter[0].ParameterName = "@PhoneBook";    
 Parameter[0].SqlDbType = SqlDbType.Structured;    
 Parameter[0].Value = PhoneTable;    

 Parameter[1].ParameterName = "@Return_Value";    
 Parameter[1].Direction = ParameterDirection.ReturnValue;    
 //Executing Procedure  
 SqlHelper.ExecuteNonQuery(this.ConnectionString, CommandType.StoredProcedure, "[NewPhoneBook]", Parameter);

Sie finden die Code-Referenz hier

6
Ajay Pattni

Ich würde diese Objekte niemals benutzen. Sie scheinen einfach nicht so nützlich zu sein. PostgreSQL verfügt jedoch über eine Methode zum Übergeben einer Tabelle an eine Funktion über jsonb. Dies ist wahrscheinlich die ideale Lösung für Sie, wenn Sie die unter Übergeben eines tabellenwertigen Parameters an eine gespeicherte Prozedur beschriebene Funktionalität erhalten möchten. Sie müssen lediglich die Datentabelle JSON zuordnen und dann die JSON an die Funktion übergeben.

Um eine Datentabelle in JSON zu konvertieren, können Sie JSON.net verwenden. Siehe auch diese Antworten zum Stapelüberlauf.

Wenn die Datentabelle zu groß ist, um in JSON serialisiert zu werden, müssen Sie möglicherweise einen Foreign Data Wrapper um etwas erstellen, das die DataRow-Objekte exportiert. Dies führt Sie auf den in "Streaming Rows genannten Pfad mit einem DataReader " . Wenn Sie kein Server-/Client-Modell benötigen, können Sie die DataTable jederzeit in CSV sichern und mit einem Foreign Data Wrapper : lesen, um diese Route zu überprüfen. file-fdw .

Ich habe es tatsächlich versucht. Ich hatte eine Menge Probleme.

  1. Es war nicht einmal einfach herauszufinden, wie man ein Paket mit nuGet installiert.
  2. Nachdem nuGet installiert wurde, obwohl es das Nr. 1-Paket auf nuGet ist, funktioniert es noch nicht mit .NET Core 2.x
  3. Durch die Installation der Beta-Version von nuGet habe ich es zum Laufen gebracht.

Konvertieren einer DataTable in JSON mit .NET Core 2.x,

using System;
using System.Data;
using Newtonsoft.Json;

class Program
{
  static void Main()
  {
    // Get the DataTable.
    DataTable table = GetTable();
    // ... Use the DataTable here with SQL.
    string json = JsonConvert.SerializeObject(table, Formatting.Indented);
    Console.WriteLine(json);

  }

  static DataTable GetTable()
  {
    // Here we create a DataTable with four columns.
    DataTable table = new DataTable();
    table.Columns.Add("Dosage", typeof(int));
    table.Columns.Add("Drug", typeof(string));
    table.Columns.Add("Patient", typeof(string));
    table.Columns.Add("Date", typeof(DateTime));

    // Here we add five DataRows.
    table.Rows.Add(25, "Indocin", "David", DateTime.Now);
    table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
    table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
    table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
    table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);

    return table;
  }
}

Sie müssten immer noch eine Verbindung zur Datenbank herstellen und den JSON in eine INSERT -Anweisung einfügen, aber das sollte einfach zu tun sein.

cmd.CommandText = "SELECT * FROM myfunc(@json)";
cmd.Parameters.AddWithValue("json", json);

Definieren Sie myfunc(jsonb) auf dem Server, und Sie sollten gut sein: Sie haben ein DataTable an PostgreSQL übergeben.

5
Evan Carroll

Ich glaube nicht, dass dies in PostgreSQL genauso möglich ist wie mit SQL Server. Abgesehen davon ist es nicht so schwer zu simulieren, wenn man sich ansieht, was unter der Haube vor sich geht. Ein häufiges Missverständnis ist, dass die Datentabelle "ganz" an die gespeicherte Prozedur übergeben wird. Dies ist nicht der Fall. Die Datentabelle wird auf der SQL Server-Seite anhand der Daten in der Datentabelle rekonstruiert. Folgendes passiert tatsächlich, wenn Sie diese Aktion in SQL Server ausführen:

  • Eine Variable des angegebenen Tabellentyps wird im Speicher erstellt.
  • Für jeden Datensatz in der Datentabelle wird eine Einfügung in die Variable vorgenommen.
  • Ein Verweis auf die Variable wird an die gespeicherte Prozedur übergeben.

Es sieht ein bisschen so aus:

DECLARE @p1 [dbo].[table_type_name];
INSERT INTO @p1 VALUES(...);
INSERT INTO @p1 VALUES(...);
-- continue until all rows have been inserted
EXEC [dbo].[sp_something] @dataTable = @p1;

Sie sehen, nichts Besonderes. Es wäre einfach, dies mithilfe temporärer Tabellen oder Staging-Tabellen zu simulieren und das SQL selbst zu generieren. Der einzige wesentliche Unterschied besteht darin, dass Sie der gespeicherten Prozedur keinen Verweis auf die Tabelle übergeben können.

Wie Evan bereits erwähnt hat, gibt es andere Möglichkeiten, Daten an PostgreSQL zu übergeben. Wenn Sie jedoch nach einer plattformübergreifenden Lösung suchen, müssen Sie sicherstellen, dass Sie nur ANSI-kompatible Methoden auswählen. Leider enthält dies keine SQL Server-Parameter mit Tabellenwerten .

So würde ich eine Lösung implementieren, die eine Art Staging-Tabelle erfordert:

  • Implementieren Sie eine Sequenz, mit der eine Sitzungs-ID zurückgegeben werden kann
  • Erstellen Sie eine Staging-Tabelle, die die erforderlichen Spalten sowie eine Spalte für die Sitzungs-ID enthält
  • Erstellen Sie eine gespeicherte Prozedur, die Daten aus der Staging-Tabelle entnimmt, die der angegebenen Sitzungs-ID entspricht, und diese mit der Zieltabelle zusammenführt.

Beispiel:

SQL

CREATE SEQUENCE seq_get_session_id START 1;

CREATE TABLE stg_table (
   session_id bigint not null,
   -- remainder of columns
);

CREATE OR REPLACE FUNCTION insert_data(_session_id BIGINT)
RETURNS void AS
$BODY$
BEGIN
    INSERT INTO my_table (...)
    SELECT /* columns */
      FROM stg_table
     WHERE session_id = _session_id;

    DELETE FROM stg_table
    WHERE session_id = _session_id;
END
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

C #

var phonebooks = GetPhoneBooks();

using (var connection = GetConnection())
{
    long sessionId;
    connection.Open();
    var transaction = connection.BeginTransaction();

    // get the session id
    using(var command = connection.CreateCommand())
    {
        command.Transaction = transaction;
        command.CommandText = "SELECT nextval('seq_get_session_id')";
        using (var reader = command.ExecuteReader())
        {
            if (!reader.Read())
                throw new InvalidOperationException("Unable to obtain session id");
            sessionId = reader.GetInt64(0);
        }       
    }

    // insert data into staging table
    using (var insertCommand = connection.CreateCommand())
    {
        insertCommand.CommandText = 
            "INSERT INTO stg_table (session_id, ...)" + 
            " VALUES (_session_id, ...)";
        insertCommand.Transaction = transaction;
        insertCommand.Parameters.AddWithValue("_session_id", sessionId);

        var p1 = insertCommand.CreateParameter();
        p1.ParameterName = "_p1";
        p1.DbType = DbType.DateTime;
        p1.Value = DateTime.Now;
        insertCommand.Parameters.Add(p1);

        // repeat above for each property that needs to be persisted...

        foreach(var phonebook in phonebooks)
        {
            p1.Value = phonebook.Date;
            // set values for any other parameters you have declared...

            insertCommand.ExecuteNonQuery();
        }    
    }

    // execute final stored procedure to merge the data
    using (var insertDataCommand = connection.CreateCommand())
    {
        insertDataCommand.CommandText = "insert_data";
        insertDataCommand.CommandType = CommandType.StoredProcedure;
        insertDataCommand.Parameters.AddWithValue("_session_id", sessionId);

        insertDataCommand.Transaction = transaction;
        insertDataCommand.ExecuteNonQuery();
    }  

    transaction.Commit();
}

Das Obige ist jedoch ein großer Overkill, wenn Sie keine Staging-Tabelle benötigen. Wenn Sie die Daten direkt in die Zieltabelle einfügen können, können Sie sie weglassen den größten Teil des obigen Codes und machen Sie einfach Folgendes:

using (var connection = GetConnection())
{
    connection.Open();
    var transaction = connection.BeginTransaction();

    using (var insertCommand = connection.CreateCommand())
    {
        insertCommand.CommandText = 
            "INSERT INTO my_table (...)" + 
            " VALUES (...)";
        insertCommand.Transaction = transaction;

        var p1 = insertCommand.CreateParameter();
        p1.ParameterName = "_p1";
        p1.DbType = DbType.DateTime;
        p1.Value = DateTime.Now;
        insertCommand.Parameters.Add(p1);

        // repeat above for each property that needs to be persisted...

        foreach(var phonebook in phonebooks)
        {
            p1.Value = phonebook.Date;
            // set values for any other parameters you have declared...

            insertCommand.ExecuteNonQuery();
        }         
    }

    transaction.Commit();
}
3
Mr.Brownstone

WIE ZU PASSIEREN

DATENTABELLE

ALS PARAMETER IN POSTGRESQL

================================================

SCHRITT 1

TABELLE ERSTELLEN, DIE SIE IN POSTGRE ALS DATIERBAR BESTANDEN WOLLEN

Beispiel…

Ich erstelle Studententyp in postgresql wie

Create Type Student As (ID-Ganzzahl, Namenstext);

- == Erstellen Sie eine physische Tabelle zu Testzwecken. Tabellenlehrer erstellen (ID-Ganzzahl, Namenstext);

Schritt 2

CREATE OR REPLACE FUNCTION public.usp_InsertStudent (ref1 refcursor, p_str_string json) RETURNS refcursor AS $ BODY $ BEGIN

Insert into  Teacher (id,name)
select id,name from json_populate_recordset(null::Student,p_str_string);

OPEN REF1 FOR
select * from  Teacher;

return  ref1;

ENDE; $ BODY $ LANGUAGE plpgsql VOLATILE COST 100;

Schritt 3

Anruf von C #

DataSet ds = new DataSet (); DataTable-Tabelle = neue DataTable (); table.Columns.Add ("id", typeof (int)); table.Columns.Add ("name", typeof (string)); table.Rows.Add (25, "ajay"); table.Rows.Add (25, "rajesh"); table.Rows.Add (25, "jayesh");

        string json = JsonConvert.SerializeObject(table, Formatting.Indented);
        string conStr = "put connection string here..";
        NpgsqlConnection conn = new NpgsqlConnection(conStr);
        conn.Open();
        string query = string.Empty;
        query = "select * from usp_InsertStudent('ref1'";
        query = query + ",p_str_string:='"+json+"'"+
         ");fetch all in " + "\"ref1\";";

         NpgsqlDataAdapter da = new NpgsqlDataAdapter(query, conn);
         da.Fill(ds);
         System.Data.DataTable dt = ds.Tables[1];
         //// connect grid to DataTable
         dataGridView1.DataSource = dt;
         dataGridView1.DataBind();
0
Ajay Pattni