Return table with columns [duplicate] - postgresql

This question already has answers here:
function returns multiple columns as a single column instead of multiple columns
(1 answer)
How to return two columns with function
(1 answer)
Record returned from function has columns concatenated
(2 answers)
Return multiple columns and rows from a function PostgreSQL instead of record
(3 answers)
Postgresql function returns composite - how do I access composite values as separate columns?
(2 answers)
Closed 4 years ago.
Here is a simple query that gives expected out.
select 1.1 as x, 1.1 as y;
x | y
-----+-----
1.1 | 1.1
(1 row)
Here the same query is placed inside a function.
CREATE OR REPLACE FUNCTION foo4(param integer)
RETURNS TABLE(x float, y float) AS
$$
DECLARE var float;
BEGIN
var = 1.1;
RETURN QUERY select var as x, var as y;
END;
$$
LANGUAGE 'plpgsql';
Here is the output:
select foo4(4);
foo4
-----------
(1.1,1.1)
(1 row)
Why does the function output the data differently? How can I make the function output into two columns?
Using PostgreSQL 10.3 and Windows 7/10.

select * from foo4(4); should give you the result you are looking for.

Try RETURN QUERY EXECUTE. That will cause the query to be dynamic instead of static. https://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#AEN63012

Related

What is wrong with my WHERE condition in Postgres? [duplicate]

This question already has answers here:
What is the difference between single quotes and double quotes in PostgreSQL?
(3 answers)
Error: Column does not exist in postgresql for update [duplicate]
(1 answer)
postgres column "X" does not exist
(1 answer)
Simple Postgresql Statement - column name does not exists
(2 answers)
Closed 2 years ago.
I am running the query SELECT * FROM app_user WHERE login_id = "john"; and getting -
ERROR: column "john" does not exist
LINE 1: SELECT * FROM public.app_user WHERE login_id = "john";
^
SQL state: 42703
Character: 48
I have also tried SELECT * FROM public.app_user WHERE login_id = "john"; and I still get the same error.
The same error also occurs with any other column but the id column(id is the only non-VARCHAR column and is the primary key).
So, SELECT * FROM app_user WHERE id = 5; is working as expected .
A snapshot of the table follows.
If you write the string in double quotes, postgres will interpret it as a column name in the WHERE clause, just use single quotes:
SELECT * FROM public.app_user WHERE login_id = 'john';

Array in postgresql [duplicate]

This question already has answers here:
Postgres: check if array field contains value?
(4 answers)
How to make a select with array contains value clause in psql
(3 answers)
Search in integer array in Postgres
(3 answers)
Closed 4 years ago.
I have a table with a column 'sample_column' which is an array.
Can anyone tell me how can I select data based on 'sample_column' in postgresql?
Example of data in sample_column: ["one","two","three"]
I want to get all data if sample_column has value "three"
Here is what I have done:
Select * from sample_table where sample_column contains 'three'
I am getting ERROR.
Any help will be appreciated.
I assume you have table as:
CREATE TABLE table_name
(
sample_column text[]
);
and you have insert data as:
insert into table_name(sample_column) values (array['one','two','three']);
insert into table_name(sample_column) values (array['yes','no']);
insert into table_name(sample_column) values (array['red','white','blue']);
now you want to find recored based on the array element:
select * from table_name where 'three' = ANY(sample_column);
I hope it helps.
Demo

Create function to compute an average of 3 values

I'm trying to write a function in postgre sql to take an average across three columns. I have written the following function:
create function xcol_avg (col1, col2, col3)
returns numeric as $$
begin
return (coalesce(col1, 0) + coalesce(col2,0) +coalesce(col3, 0))/
case when (col 1 is null or col1 = 0 then 0 else 1 end +
case when (col 2 is null or col2 = 0 then 0 else 1 end +
case when (col 3 is null or col3 = 0 then 0 else 1 end;
end
What is the problem with my code? Also, is there a way to get the function to return null if it ends up dividing by 0? Any help is really appreciated.
Thanks!
Actually, you can make a function that will use a variable number of arguments and depending on their number compute the average. In Postgres there's a word VARIADIC for such things:
SQL functions can be declared to accept variable numbers of arguments, so long as all the "optional" arguments are of the same data type
Function code:
CREATE FUNCTION xcol_avg(numeric, VARIADIC numeric[])
RETURNS numeric
LANGUAGE plpgsql
IMMUTABLE
AS $$
BEGIN
RETURN (SELECT AVG(vals) FROM unnest($2 || ARRAY[$1]) t(vals));
END;
$$;
Use case with different number of arguments:
select xcol_avg(1,6); -- returns 3.5
select xcol_avg(1,5.5,4); -- returns 3.5
select xcol_avg(1,2,3,4,5,6,7); -- returns 4
Click on this Button to try this online.
Explanation:
Marking a function as IMMUTABLE improves the execution time by allowing the optimizer to pre-evaluate the function. Immutable functions cannot modify the database and are guaranteed to always return the same results when called with the same input.
Declaring the last parameter of a function as VARIADIC which has to be of an array type lets you provide optional arguments that will be passed to the function as an array. Note that you don't explicitly write the array, you just list your parameters as you normally would.
unnest() is a function that returns a set of rows by expanding an array. In other words it's "unpacking" the array elements into separate rows
|| is an array operator that provides the array-to-array concatenation. Here it serves the purpose of connecting the first (required) argument with the rest given in a VARIADIC array.
AVG() is an aggregate function that computes an average of all input values. In our case it would take "unpacked" rows from a column named vals and compute the average.
With this solution you don't need to worry about dividing by zero, as at least one argument is required and avg() is doing the job you wanted to do manually by building up the denominator.
Apply it in a query:
This function would also work for computing an average of multiple columns in a row. Consider a table tbl with columns name, cost1, cost2, cost3 and below statement:
SELECT
name, cost1, cost2, cost3,
xcol_avg(cost1, cost2, cost3) AS average_cost
FROM tbl
For more general information about CREATE FUNCTION check the resourceful documentation.

Trying to create aggregate function in PostgreSQL

I'm trying to create new aggregate function in PostgreSQL to use instead of the sum() function
I started my journey in the manual here.
Since I wanted to create a function that takes an array of double precision values, sums them and then does some additional calculations I first created that final function:
takes double precision as input and gives double precision as output
DECLARE
v double precision;
BEGIN
IF tax > 256 THEN
v := 256;
ELSE
v := tax;
END IF;
RETURN v*0.21/0.79;
END;
Then I wanted to create the aggregate function that takes an array of double precision values and puts out a single double precision value for my previous function to handle.
CREATE AGGREGATE aggregate_ee_income_tax (float8[]) (
sfunc = array_agg
,stype = float8
,initcond = '{}'
,finalfunc = eeincometax);
What I get when I run that command is:
ERROR: function array_agg(double precision, double precision[]) does
not exist
I'm somewhat stuck here, because the manual lists array_agg() as existing function. What am I doing wrong?
Also, when I run:
\da
List of aggregate functions
Schema | Name | Result data type | Argument data types | Description
--------+------+------------------+---------------------+-------------
(0 rows)
My installation has no aggregate functions at all? Or does only list user defined functions?
Basically what I'm trying to understand:
1) Can I use an existing functions to sum up my array values?
2) How can I find out about input and ouptut data types of functions? Docs claim that array_agg() takes any kind of input.
3) What is wrong with my own aggregate function?
Edit 1
To give more information and clearer picture of what I'm trying to achieve:
I have one huge query over several tables which goes something like this:
SELECT sum(tax) ... from (SUBQUERY) as foo group by id
I want to replace that sum function with my own aggregate function so I don't have to do additional calculations on backend - since they can all be done on database level.
Edit 2
Accepted Ants's answer. Since final solution comes from comments I post it here for reference:
CREATE AGGREGATE aggregate_ee_income_tax (float8)
(
sfunc = float8pl
,stype = float8
,initcond = '0.0'
,finalfunc = eeincometax
);
Array agg is an aggregate function not a regular function, so it can't be used as a state transition function for a new aggregate. What you want to do is to create an aggregate function which has a state transition function that is identical to array_agg and a custom final func.
Unfortunately the state transition function of array_agg is defined in terms of an internal datatype so it can't be reused. Fortunately there is an existing function in core that already does what you want.
CREATE AGGREGATE aggregate_ee_income_tax (float8)(
sfunc = array_append,
stype = float8[],
initcond = '{}',
finalfunc = eeincometax);
Also note that you had your types mixed up, you probably want aggregate a set of floats to an array, not a set of arrays to a float.
In addition to #Ants excellent advice:
1.) Your final function could be simplified to:
CREATE FUNCTION eeincometax(float8)
RETURNS float8 LANGUAGE SQL AS
$func$
SELECT (least($1, 256) * 21) / 79
$func$;
2.) It seems like you are dealing with money? In this case I would strongly advise to use the type numeric (preferred) or money for the purpose. Floating point operations are often not precise enough.
3.) The initial condition of the aggregate can simply be just 0:
CREATE AGGREGATE aggregate_ee_income_tax(float8)
(
sfunc = float8pl
,stype = float8
,initcond = 0
,finalfunc = eeincometax
);
4.) In your case (least(sum(tax), 256) * 21) / 79 is probably faster than your custom aggregate. Aggregate functions provided by PostgreSQL are written in C and optimized for performance. I would use that instead.

Function in Postgres to convert a varchar to a big integer

I have a varchar column in Postgres 8.3 that holds values like: '0100011101111000'
I need a function that would consider that string to be a number in base 2 and spits out the numeric in base 10. Makes sense?
So, for instance:
'000001' -> 1.0
'000010' -> 2.0
'000011' -> 3.0
Thanks!
Cast to a bit string then to an integer.
An example:
'1110'::bit(4)::integer -> 14
Though you had varying length examples, and were after bigint, so instead use bit(64) and pad the input with zeroes using the lpad function.
lpad('0100011101111000',64,'0')::bit(64)::bigint
Here's a complete example...
create temp table examples (val varchar(64));
insert into examples values('0100011101111000');
insert into examples values('000001');
insert into examples values('000010');
insert into examples values('000011');
select val,lpad(val,64,'0')::bit(64)::bigint as result from examples;
The result of the select is:
val | result
------------------+--------
0100011101111000 | 18296
000001 | 1
000010 | 2
000011 | 3
(4 rows)