In postgresql- what is the equivalent of stored procedure with table valued paramater(MSSQL)?
-
1There's no equivalent AFAIK. There are many workarounds though. A function can accept an array of composite types, a cursor, temp table name, etc. https://stackoverflow.com/questions/43811093/how-to-pass-multiple-rows-to-postgresql-function https://stackoverflow.com/questions/18219991/passing-a-resultset-into-a-postgresql-function – pumbo Nov 24 '17 at 05:38
-
1Please explain the actual, underlying problem you are trying to solve, not the solution that thinks would solve that. – Nov 24 '17 at 06: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. – HamidKhan Nov 25 '17 at 06:23
3 Answers
@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);

- 89
- 3
-
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. – User12111111 Jan 06 '20 at 09:45
-
-
https://www.slideshare.net/pgday_seoul/pgdayseoul-2017-4-composite-typejson-tvpwith-c-java – 지현명 Feb 25 '20 at 23:41
-
Recommended way to json. Attach my full source. https://gitlab.com/gwise/tvp_for_json_csharp – 지현명 Feb 25 '20 at 23:51
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.

- 8,458
- 13
- 59
- 133

- 42,331
- 5
- 91
- 94
-
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 Nov 25 '17 at 06:25
-
1@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. – Pavel Stehule Nov 25 '17 at 08:03
-
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 Nov 25 '17 at 09:04
-
@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. – Jan 07 '18 at 16:55
-
@HamidKhan, Option 1 - Pass jsonb parameter to postgres function and use jsonb_to_recordset function to get tabular structure. Refer - https://levelup.gitconnected.com/how-to-query-a-json-array-of-objects-as-a-recordset-in-postgresql-a81acec9fbc5 Option 2 - Use staging table and insert records https://dba.stackexchange.com/questions/193827/pass-datatable-as-parameter-in-postgresql – Maulik Modi Apr 16 '21 at 08:41
-
@PavelStehule _"the PLpgSQL is much more powerful language than T-SQL"_ - I'm curious: in my experience T-SQL is only _slightly_ worse than Postgre's dialect, and of course they're both equally Turing complete... The areas where PostgreSQL is far superior aren't in its SQL language nor its procedural SQL, but are due to underlying engine features (like deferred-constraints and query features like `DISTINCT ON`) - and a T-SQL version of your posted code (to loop from 10 to 20) would be just as verbose. Also, what "varchar limits" are you referring to? `varchar(max)` works fine in T-SQL. – Dai Aug 03 '22 at 11:18
-
@Dai - I am not sure, but T-SQL still has not `FOR` statement - so iteration over query needs to be implemented more explicitly - like iteration over cursor. Exception handling, an possibility to work with an arrays, ... there are lot of features that PL/pgSQL has twenty years, and they are maybe fresh in T-SQL – Pavel Stehule Aug 03 '22 at 19:50
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) });

- 5,709
- 12
- 53
- 82