16

In postgresql- what is the equivalent of stored procedure with table valued paramater(MSSQL)?

3
  • 1
    There's no equivalent AFAIK. There are many workarounds though. A function can accept an array of composite types, a cursor, temp table name, etc. stackoverflow.com/questions/43811093/… stackoverflow.com/questions/18219991/… Commented Nov 24, 2017 at 5:38
  • 1
    Please explain the actual, underlying problem you are trying to solve, not the solution that thinks would solve that. Commented Nov 24, 2017 at 6:35
  • I need to migrate db(no of tables and SP's with TVP) from SQL server to Postgres. So finding out easy way to migrate SP having TVP. Commented Nov 25, 2017 at 6:23

3 Answers 3

8

PostgreSQL has no table variables. The most similar type is a composite array:

create type foo_typ as (a int, b int);

do $$
declare
  f foo_typ[];
  r foo_typ;
begin
  f := ARRAY(SELECT row(10, 20)::foo_typ from generate_series(1,10));
  for r in select * from unnest(f) g(v)
  loop
    raise notice 'a:%, b:%', r.a, r.b;
  end loop;
end;
$$;
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
NOTICE:  a:10, b:20
DO

Writing stored procedures in PostgreSQL, you are practically starting from zero coming from T-SQL in terms of syntax familiarity. The PostgreSQL syntax is similar to Oracle and DB2 - but very different to SQL Server.

Sign up to request clarification or add additional context in comments.

7 Comments

I need to migrate db(no of tables and SP's with TVP) from SQL server to Postgres. So finding out easy way to migrate SP having TVP. Can you please suggest easy/suitable way for the same.Thank you
@HamidKhan - there are not any easy way - MSSQL has significantly different design than other databases - the rewriting is only one possible - on second hand - the PLpgSQL is much more powerful language than T-SQL and limits for varchar are significantly better higher in Postgres.
Which type I can use in place of TVP to rewrite SP's in postgres.Can you please suggest me a reference link for same. Thanks in advance
@HamidKhan: Pavel's answer shows you what to use. The equivalent is an array of e.g. a table type or a user defined type.
@HamidKhan, Option 1 - Pass jsonb parameter to postgres function and use jsonb_to_recordset function to get tabular structure. Refer - levelup.gitconnected.com/… Option 2 - Use staging table and insert records dba.stackexchange.com/questions/193827/…
|
7

@HamidKhan -Is your development language Java or C #?

CREATE TABLE public.employee (
  emp_id INTEGER NOT NULL,
  emp_nm VARCHAR(40),
  first_in_time TIMESTAMP WITH TIME ZONE DEFAULT clock_timestamp(),
  last_chg_time TIMESTAMP WITH TIME ZONE DEFAULT clock_timestamp(),
  CONSTRAINT employee_pkey PRIMARY KEY(emp_id)
)
WITH (oids = false);

CREATE TYPE public.employee_udt AS (
  emp_id INTEGER,
  emp_nm VARCHAR(40)
);

--c# code 1

public class EmployeeUdt
{
    [PgName("emp_id")] 
    public int EmpId { get; set; } 

    [PgName("emp_nm")]
    public string EmpNm { get; set; }
}

--c# code 2

List<EmployeeUdt> lst_param = new List<EmployeeUdt>();

for (int i = 0; i < this.dataGridView1.Rows.Count; i++)
{
lst_param.Add(
new EmployeeUdt
{
    EmpId = Convert.ToInt32(this.dataGridView1[0, i].Value),
    EmpNm = this.dataGridView1[1, i].Value.ToString()
}
);
}

var _param = new[] {
new NpgsqlParameter
{
    ParameterName="p_employee",
    NpgsqlDbType = NpgsqlDbType.Composite,
    SpecificType = typeof(EmployeeUdt[]),
    NpgsqlValue = lst_param
}

};

SqlHelper.ExecuteNonQuery<EmployeeUdt>(this.connstring, "usp_set_emp", _param);

4 Comments

I have a similar situation. Which version of npgsql did you use. The version that I am using is 4.0.10, which doesn't have NpgsqlDBType.Composite. Do you have any alternative for this.
\Npgsql.3.2.5\lib\net451\Npgsql.dll
Recommended way to json. Attach my full source. gitlab.com/gwise/tvp_for_json_csharp
5

You can use a JSON array as an input with jsonb_to_recordset(). That's the easiest way I've found. Just make a JSON array filled with objects. I'm not sure it's as fast as a true table value parameter in SQL Server but it only requires one request to insert or update many values.

This is an example from my code base using Dapper. Notice how I convert the array to a JSON string. Then it uses jsonb_to_recordset to conver that to a table.

await cnTeam.ExecuteAsync(@"
update enterprisecontact
set
primarysource_contactid = x.primarysource_contactid,
primarysource_contact_recordtype = x.primarysource_contact_recordtype,
primarysource_accountid = x.primarysource_accountid,
primarysource_accountname = x.primarysource_accountname,
primarysource_createdate = x.primarysource_createdate,
primarysource_updatedate = x.primarysource_updatedate
from (
    select * from jsonb_to_recordset(:jsoninput::jsonb) as y(
        emailaddress text, 
        primarysource_contactid text,
        primarysource_contact_recordtype text,
        primarysource_accountid text,
        primarysource_accountname text,
        primarysource_createdate timestamp with time zone,
        primarysource_updatedate timestamp with time zone
        )
) x
where enterprisecontact.emailaddress = x.emailaddress
", new { jsoninput = JsonConvert.SerializeObject(chunk) });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.