{"id":15596,"date":"2021-02-03T13:02:23","date_gmt":"2021-02-03T12:02:23","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/"},"modified":"2021-02-03T13:02:23","modified_gmt":"2021-02-03T12:02:23","slug":"an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/","title":{"rendered":"An introduction into server side programming in PostgreSQL &#8211; 1 &#8211; SQL functions, basics"},"content":{"rendered":"<p>Over the last years I&#8217;ve seen many different applications running against PostgreSQL. The use cases vary from simple applications, which only use basic data types and a few tables and views, to complex applications with custom types, more specific data types like <a href=\"https:\/\/www.postgresql.org\/docs\/current\/datatype-json.html\" target=\"_blank\" rel=\"noopener\">jsonb<\/a> or <a href=\"https:\/\/www.postgresql.org\/docs\/current\/rangetypes.html\" target=\"_blank\" rel=\"noopener\">range types<\/a>, that use hundreds of schemas\/tables\/views\/materialized views etc. Surprisingly only a few of them make use of functions and procedures in PostgreSQL. I&#8217;ve always told people to process the data where it is, and usually the data is in the database, as this is best for performance and enables you to make us of advanced features of PostgreSQL. This does, of course, not only apply to PostgreSQL but to all other databases systems as well. This usually leads to discussion about being independent of the underlying databases and then it gets religious. While I understand the developer\/business owner&#8217;s point of view of being as much independent of the database as possible, makes it easier to migrate from one database system to another in the future, this decision closes many doors when it comes to getting the maximum out of the database. <\/p>\n<p><!--more--><\/p>\n<p>The most simple function you can create in PostgreSQL is a <a href=\"https:\/\/www.postgresql.org\/docs\/current\/xfunc-sql.html\" target=\"_blank\" rel=\"noopener\">SQL function<\/a>. A SQL functions contain one or more SQL statements and either return nothing, one row or a set of rows. To get started lets create a standard <a href=\"https:\/\/www.postgresql.org\/docs\/current\/pgbench.html\" target=\"_blank\" rel=\"noopener\">pgbench<\/a> schema with a couple of rows:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# ! pgbench -i -s 10 postgres\ndropping old tables...\nNOTICE:  table \"pgbench_accounts\" does not exist, skipping\nNOTICE:  table \"pgbench_branches\" does not exist, skipping\nNOTICE:  table \"pgbench_history\" does not exist, skipping\nNOTICE:  table \"pgbench_tellers\" does not exist, skipping\ncreating tables...\ngenerating data (client-side)...\n1000000 of 1000000 tuples (100%) done (elapsed 2.20 s, remaining 0.00 s)\nvacuuming...\ncreating primary keys...\ndone in 3.52 s (drop tables 0.00 s, create tables 0.04 s, client-side generate 2.27 s, vacuum 0.30 s, primary keys 0.90 s).\npostgres=# d\n              List of relations\n Schema |       Name       | Type  |  Owner   \n--------+------------------+-------+----------\n public | pgbench_accounts | table | postgres\n public | pgbench_branches | table | postgres\n public | pgbench_history  | table | postgres\n public | pgbench_tellers  | table | postgres\n(4 rows)\n<\/pre>\n<p>One of the most simple SQL functions is something like this:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function get_bid_for_aid_1 () returns int\n           as $$\n           select bid from pgbench_accounts where aid = 1;\n           $$ language SQL;\nCREATE FUNCTION\n<\/pre>\n<p>This really is not rocket science but it is a good starting point to understand the concepts. PostgreSQL uses the so called dollar quoting. That means, everything between the first &#8220;$$&#8221; and the last &#8220;$$&#8221; is the body of the function. This makes it easier to write sting literals without escaping like, e.g. single or double quotes (a more detailed description can be found <a href=\"https:\/\/www.postgresql.org\/docs\/current\/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS\" target=\"_blank\" rel=\"noopener\">here<\/a>). If you want to use a tag with dollar quoting you can do that as well:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function get_bid_for_aid_1_tmp () returns int\n           as $my_tag$\n           select bid from pgbench_accounts where aid = 1;\n           $my_tag$ language SQL;\nCREATE FUNCTION\n<\/pre>\n<p>Side note: There is nothing like in &#8220;invalid object&#8221; as you might know that from Oracle. If your function body contains errors it will not be stored in the database, you&#8217;ll have to fix that first:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function get_bid_for_aid_1_tmp_1 () returns int\n           as $my_tag$\n           select bid from pgbench_accountsXX where aid = 1;\n           $my_tag$ language SQL;\nERROR:  relation \"pgbench_accountsxx\" does not exist\nLINE 3: select bid from pgbench_accountsXX where aid = 1;\n<\/pre>\n<p>More information about this behavior can be found <a href=\"https:\/\/www.dbi-services.com\/blog\/postgresql-check_function_bodies-what-is-it-good-for\/\" target=\"_blank\" rel=\"noopener\">here<\/a>. Coming back to our initial function: As soon as the function is stored in PostgreSQL you can reference it in your SQL queries:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# select * from get_bid_for_aid_1();\n get_bid_for_aid_1 \n-------------------\n                 1\n(1 row)\n<\/pre>\n<p>Right now this function is quite limited as it returns the bid only for aid=1. To make that a bit more re-usable can you make use of parameters:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# drop function get_bid_for_aid_1();\nDROP FUNCTION\npostgres=# create or replace function get_bid_for_aid (int) returns int\n           as $my_tag$\n           select bid from pgbench_accounts where aid = $1;\n           $my_tag$ language SQL;\nCREATE FUNCTION\npostgres=# select * from get_bid_for_aid(1);\n get_bid_for_aid \n-----------------\n               1\n(1 row)\n<\/pre>\n<p>Now the function is more flexible, as you can ask for any bid for a given aid. But there is even more we can do, to make the function more readable. Instead of specifying just the data type for the input parameter we can give the parameter a name:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function get_bid_for_aid (pn_aid int) returns int\n           as $my_tag$\n           select bid from pgbench_accounts where aid = pn_aid;\n           $my_tag$ language SQL;\nCREATE FUNCTION\npostgres=# select * from get_bid_for_aid(1);\n get_bid_for_aid \n-----------------\n               1\n(1 row)\n<\/pre>\n<p>Although this does not change the behavior of the function, it makes the function easier to read and we recommend to work with those named parameters instead of only specifying the data types. Especially when the body of a function becomes quite large and it uses many parameters, it saves you quite some scrolling forward and backward because you already know the data type from the parameter name (or at least you should be able to guess it).<\/p>\n<p>You are not limited to use a function in the from clause of your statement. Actually you can use the function wherever you want, as long as the result is valid SQL, e.g. in the where clause:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# select count(*) \n             from pgbench_accounts \n            where bid = get_bid_for_aid (1);\n count  \n--------\n 100000\n(1 row)\n<\/pre>\n<p>By now we used one simple select with our function, but you can also modify your data using SQL functions:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function upd_pgbench_account_for_aid ( pn_aid int, pv_filler character ) returns void\n           as $$\n             update pgbench_accounts\n                set filler = pv_filler\n              where aid = pn_aid;\n           $$ language SQL;\nCREATE FUNCTION\npostgres=# select * from upd_pgbench_account_for_aid (1,'dummy'); \n upd_pgbench_account_for_aid \n-----------------------------\n \n(1 row)\n\npostgres=# select filler from pgbench_accounts where aid = 1;\n                                        filler                                        \n--------------------------------------------------------------------------------------\n dummy                                                                               \n(1 row)\npostgres=# select * from upd_pgbench_account_for_aid (pv_filler=&gt;'dummy2',pn_aid=&gt;1); \n upd_pgbench_account_for_aid \n-----------------------------\n \n(1 row)\n\npostgres=# select filler from pgbench_accounts where aid = 1;\n                                        filler                                        \n--------------------------------------------------------------------------------------\n dummy2                                                                              \n(1 row)\n<\/pre>\n<p>There are a couple of things to note here:<\/p>\n<ul>\n<li>A function does not need to return anything and you can specify that by using &#8220;void&#8221; as the return type<\/li>\n<li>You can use DML statements in SQL functions&lt;\/p\n<li>You can use more than one parameter (100 by default)<\/li>\n<li>You can use named parameters when calling the function as well, and if you do that, the order of the parameters does not matter. This again improves readability.\n<\/ul>\n<p>But there is more you can do, consider this simple example:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function delete_and_add ( pn_aid int, pv_filler character ) returns int\n           as $$\n             delete\n               from pgbench_accounts\n              where aid = pn_aid;\n             insert into pgbench_accounts \n                    select max(aid)+1, null, null, pv_filler\n                      from pgbench_accounts\n             returning aid;\n           $$ language sql;\nCREATE FUNCTION\npostgres=# select * from delete_and_add (1,'xxxx');\n delete_and_add \n----------------\n        1000001\n(1 row)\n\npostgres=# select * from pgbench_accounts where aid = 1000001;\n   aid   | bid | abalance |                                        filler                                        \n---------+-----+----------+--------------------------------------------------------------------------------------\n 1000001 |     |          | xxxx                                                                                \n(1 row)\n<\/pre>\n<p>A function is not restricted to a single statement, you can combine more than one statement, as you like and as it makes sense for you. Using the <a href=\"https:\/\/www.postgresql.org\/docs\/current\/sql-insert.html\" target=\"_blank\" rel=\"noopener\">returning clause<\/a> to get the new value(s) back from the function. This is actually not specific to functions but to the insert statement, but it is anyway good to know.<\/p>\n<p>If you combine multiple statements into SQL function there are some rules that apply:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function f_dummy() returns int\npostgres-# as $$ \npostgres$#   select 1;\npostgres$#   select 2;\npostgres$#   select 3;\npostgres$# $$ language sql;\nCREATE FUNCTION\npostgres=# select * from f_dummy();\n f_dummy \n---------\n       3\n(1 row)\n<\/pre>\n<p>Combining multiple statements into one function in such a way only gives you the last result. If the last statement of a SQL function does not return anything but the signature of the function specifies a return type you&#8217;ll run into an error (obviously):<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# create or replace function f_dummy_2() returns int\npostgres-# as $$ \npostgres$#   select 1;\npostgres$#   select 2;\npostgres$#   select 3;\npostgres$#   insert into pgbench_accounts \npostgres$#          values ( -1,1,1,'aaaaa');\npostgres$# $$ language sql;\nCREATE FUNCTION\npostgres=# select * from f_dummy_2();\nERROR:  return type mismatch in function declared to return integer\nDETAIL:  Function's final statement must be SELECT or INSERT\/UPDATE\/DELETE RETURNING.\nCONTEXT:  SQL function \"f_dummy_2\" during startup\npostgres=# \n<\/pre>\n<p>Note that transaction control is not allowed in functions, this needs to happen outside, e.g.:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# begin;\nBEGIN\npostgres=*# select delete_and_add ( pn_aid=&gt;5, pv_filler=&gt;'ddd' );\n delete_and_add \n----------------\n        1000002\n(1 row)\n\npostgres=*# rollback;\nROLLBACK\npostgres=# select * from pgbench_accounts where aid = 1000002;\n aid | bid | abalance | filler \n-----+-----+----------+--------\n(0 rows)\n<\/pre>\n<p>The last point for today: If you want to edit\/view your functions in psql there are the &#8220;df&#8221; and &#8220;ef&#8221; shortcuts. The first one will show you all your functions:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres-# df\n                                          List of functions\n Schema |            Name             | Result data type |         Argument data types         | Type \n--------+-----------------------------+------------------+-------------------------------------+------\n public | delete_and_add              | integer          | pn_aid integer, pv_filler character | func\n public | f_dumm                      | integer          |                                     | func\n public | f_dummy                     | integer          |                                     | func\n public | f_dummy_2                   | integer          |                                     | func\n public | f_dummy_3                   | void             |                                     | func\n public | get_bid_for_aid             | integer          | pn_aid integer                      | func\n public | get_bid_for_aid_1_tmp       | integer          |                                     | func\n public | get_bid_for_aid_1_tmp_1     | integer          |                                     | func\n public | upd_pgbench_account_for_aid | void             | pn_aid integer, pv_filler character | func\n<\/pre>\n<p>The second one is used to directly edit the function:<\/p>\n<pre class=\"brush: sql; gutter: true; first-line: 1\">\npostgres=# ef f_dummy\npostgres=# CREATE OR REPLACE FUNCTION public.f_dummy()\n RETURNS integer\n LANGUAGE sql\nAS $function$ \n  select 1;\n  select 2;\n  select 3;\n  select 4;\n$function$\npostgres-# \npostgres-# ;\nCREATE FUNCTION\n<\/pre>\n<p>In the next post we&#8217;ll look into more advanced topics when it comes to SQL functions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Over the last years I&#8217;ve seen many different applications running against PostgreSQL. The use cases vary from simple applications, which only use basic data types and a few tables and views, to complex applications with custom types, more specific data types like jsonb or range types, that use hundreds of schemas\/tables\/views\/materialized views etc. Surprisingly only [&hellip;]<\/p>\n","protected":false},"author":29,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229],"tags":[77],"type_dbi":[],"class_list":["post-15596","post","type-post","status-publish","format-standard","hentry","category-database-administration-monitoring","tag-postgresql"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>An introduction into server side programming in PostgreSQL - 1 - SQL functions, basics - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"An introduction into server side programming in PostgreSQL - 1 - SQL functions, basics\" \/>\n<meta property=\"og:description\" content=\"Over the last years I&#8217;ve seen many different applications running against PostgreSQL. The use cases vary from simple applications, which only use basic data types and a few tables and views, to complex applications with custom types, more specific data types like jsonb or range types, that use hundreds of schemas\/tables\/views\/materialized views etc. Surprisingly only [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-02-03T12:02:23+00:00\" \/>\n<meta name=\"author\" content=\"Daniel Westermann\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@westermanndanie\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Daniel Westermann\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/\"},\"author\":{\"name\":\"Daniel Westermann\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"headline\":\"An introduction into server side programming in PostgreSQL &#8211; 1 &#8211; SQL functions, basics\",\"datePublished\":\"2021-02-03T12:02:23+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/\"},\"wordCount\":905,\"commentCount\":0,\"keywords\":[\"PostgreSQL\"],\"articleSection\":[\"Database Administration &amp; Monitoring\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/\",\"name\":\"An introduction into server side programming in PostgreSQL - 1 - SQL functions, basics - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"datePublished\":\"2021-02-03T12:02:23+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"An introduction into server side programming in PostgreSQL &#8211; 1 &#8211; SQL functions, basics\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/8d08e9bd996a89bd75c0286cbabf3c66\",\"name\":\"Daniel Westermann\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g\",\"caption\":\"Daniel Westermann\"},\"description\":\"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\\\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.\",\"sameAs\":[\"https:\\\/\\\/x.com\\\/westermanndanie\"],\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/daniel-westermann\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"An introduction into server side programming in PostgreSQL - 1 - SQL functions, basics - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/","og_locale":"en_US","og_type":"article","og_title":"An introduction into server side programming in PostgreSQL - 1 - SQL functions, basics","og_description":"Over the last years I&#8217;ve seen many different applications running against PostgreSQL. The use cases vary from simple applications, which only use basic data types and a few tables and views, to complex applications with custom types, more specific data types like jsonb or range types, that use hundreds of schemas\/tables\/views\/materialized views etc. Surprisingly only [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/","og_site_name":"dbi Blog","article_published_time":"2021-02-03T12:02:23+00:00","author":"Daniel Westermann","twitter_card":"summary_large_image","twitter_creator":"@westermanndanie","twitter_misc":{"Written by":"Daniel Westermann","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/"},"author":{"name":"Daniel Westermann","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"headline":"An introduction into server side programming in PostgreSQL &#8211; 1 &#8211; SQL functions, basics","datePublished":"2021-02-03T12:02:23+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/"},"wordCount":905,"commentCount":0,"keywords":["PostgreSQL"],"articleSection":["Database Administration &amp; Monitoring"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/","url":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/","name":"An introduction into server side programming in PostgreSQL - 1 - SQL functions, basics - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2021-02-03T12:02:23+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/an-introduction-to-server-side-programming-in-postgresql-1-sql-functions-basics\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"An introduction into server side programming in PostgreSQL &#8211; 1 &#8211; SQL functions, basics"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/8d08e9bd996a89bd75c0286cbabf3c66","name":"Daniel Westermann","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/31350ceeecb1dd8986339a29bf040d4cd3cd087d410deccd8f55234466d6c317?s=96&d=mm&r=g","caption":"Daniel Westermann"},"description":"Daniel Westermann is Principal Consultant and Technology Leader Open Infrastructure at dbi services. He has more than 15 years of experience in management, engineering and optimization of databases and infrastructures, especially on Oracle and PostgreSQL. Since the beginning of his career, he has specialized in Oracle Technologies and is Oracle Certified Professional 12c and Oracle Certified Expert RAC\/GridInfra. Over time, Daniel has become increasingly interested in open source technologies, becoming \u201cTechnology Leader Open Infrastructure\u201d and PostgreSQL expert. \u00a0Based on community or EnterpriseDB tools, he develops and installs complex high available solutions with PostgreSQL. He is also a certified PostgreSQL Plus 9.0 Professional and a Postgres Advanced Server 9.4 Professional. He is a regular speaker at PostgreSQL conferences in Switzerland and Europe. Today Daniel is also supporting our customers on AWS services such as AWS RDS, database migrations into the cloud, EC2 and automated infrastructure management with AWS SSM (System Manager). He is a certified AWS Solutions Architect Professional. Prior to dbi services, Daniel was Management System Engineer at LC SYSTEMS-Engineering AG in Basel. Before that, he worked as Oracle Developper &amp;\u00a0Project Manager at Delta Energy Solutions AG in Basel (today Powel AG). Daniel holds a diploma in Business Informatics (DHBW, Germany). His branch-related experience mainly covers the pharma industry, the financial sector, energy, lottery and telecommunications.","sameAs":["https:\/\/x.com\/westermanndanie"],"url":"https:\/\/www.dbi-services.com\/blog\/author\/daniel-westermann\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/15596","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/29"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=15596"}],"version-history":[{"count":0,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/15596\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=15596"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=15596"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=15596"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=15596"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}