PostgreSQL function giving all rows but not in key value pair format? - postgresql

I have table called users in PostgreSQL.I want to get all users in table from my Laravel application.
I can get from table directly as:
$testData = DB::table('users')->get();
output is:
[{"id":1,"name":"Chris Sevilleja","username":"sevilayha","email":"chris#scotch.io","password":"$2y$08$i\/ATa68ierqRL47ZxHX4EesJGEcdtKPckZs8GDGpYS.IR4aaQn.\/q","created_at":"2016-09-07 09:32:41","updated_at":"2016-09-07 09:32:41"},{"id":2,"name":"Bemagoni chandrashekar","username":"chandrashekar","email":"chandrashekar#zessta.com","password":"$2y$08$QG9JsAerYp3UYpXNNyImhuz\/6hiWv8XpURpJX1uJ.hAm8l1RG2JrC","created_at":"2016-09-07 09:32:41","updated_at":"2016-09-07 09:32:41"},{"id":3,"name":"dwefr","username":"ewre","email":"ewrt#egyfrhgt.com","password":"$2y$08$s2XBZvoAvpEqjjhbx8QPw.eSe5TIuJC25XbaFkTskzAKAGi99QWga","created_at":"2016-09-07 09:34:27","updated_at":"2016-09-07 09:34:27"},{"id":4,"name":"r3t54y6u677i","username":"retrytyu","email":"etyru#dddj.com","password":"$2y$08$Xb0Xm4KwdSwcBSHX0F6ETOWU60X.NO5D7\/uwVv\/xUAXTUS8LSPCLu","created_at":"2016-09-07 09:46:26","updated_at":"2016-09-07 09:46:26"},{"id":5,"name":"r3t45y6u","username":"ertrh","email":"435t4y65#sss.com","password":"$2y$08$36DLu49nZ2YOWtU.c625meiyi3\/fmsHxiTuxIU9z9UcyrbIpFSKKW","created_at":"2016-09-07 10:02:05","updated_at":"2016-09-07 10:02:05"},{"id":6,"name":"ewrtryuyj","username":"ryt","email":"wrewtey#sssks.com","password":"$2y$08$GULHtX3GGXPGgm8gA9yDbeawZlQ5QwD2TX7nrCvEU4j7jrSgPWAQO","created_at":"2016-09-07 10:04:17","updated_at":"2016-09-07 10:04:17"},{"id":7,"name":"chandu","username":"chandu","email":"ch1235hdhd#dhdjd.com","password":"$2y$08$gpAhcl\/Sg.lGvb.zk.I\/m.PfcttGI6OPFMsMxQVm15dYOtQDvIWSG","created_at":"2016-09-07 10:06:18","updated_at":"2016-09-07 10:06:18"},{"id":8,"name":"dewfergt","username":"erwrgf","email":"fgf#dgrf.com","password":"$2y$08$ikYAXV1prZsEj2MPxXM4S.Tqn160Jv25cFOQLghK8ptFiSBaIFGZO","created_at":"2016-09-07 10:07:20","updated_at":"2016-09-07 10:07:20"},{"id":9,"name":"rteryt","username":"wrwter","email":"wretr#gjjd.com","password":"$2y$08$pkOUBl1NlNdBShNWiklya.0zlPzPrEH2edCfvdCiHLnj80GY1sdtm","created_at":"2016-09-08 07:11:46","updated_at":"2016-09-08 07:11:46"},{"id":10,"name":"Raghu","username":"raghu","email":"raghu#gdgdjd.com","password":"$2y$08$m9wke.vvTTZytYw91I4\/q.qxKoCobLOW7dbCvs66xFyJyy2R9phni","created_at":"2016-09-10 10:06:40","updated_at":"2016-09-10 10:06:40"},{"id":11,"name":"wewert","username":"ewretr","email":"ewrtey#vsss.com","password":"$2y$08$IXD0eXYTPPGE1MfALonEFey0lr\/KBMZ0.3AIO3sWVgu7IZdWhXwTG","created_at":"2016-09-12 07:48:58","updated_at":"2016-09-12 07:48:58"}]
Through PostgreSQL function calling:
my PostgreSQL function:
-- Function: public."RegiterUsers2"()
-- DROP FUNCTION public."RegiterUsers2"();
CREATE OR REPLACE FUNCTION public."RegiterUsers2"()
RETURNS SETOF users AS
'select * from users'
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION public."RegiterUsers2"()
OWNER TO postgres;
Laravel code:
$allUserData=DB::select('SELECT public."RegiterUsers2"()')
output:
[{"RegiterUsers2":"(1,\"Chris Sevilleja\",sevilayha,chris#scotch.io,$2y$08$i\/ATa68ierqRL47ZxHX4EesJGEcdtKPckZs8GDGpYS.IR4aaQn.\/q,\"2016-09-07 09:32:41\",\"2016-09-07 09:32:41\")"},{"RegiterUsers2":"(2,\"Bemagoni chandrashekar\",chandrashekar,chandrashekar#zessta.com,$2y$08$QG9JsAerYp3UYpXNNyImhuz\/6hiWv8XpURpJX1uJ.hAm8l1RG2JrC,\"2016-09-07 09:32:41\",\"2016-09-07 09:32:41\")"},{"RegiterUsers2":"(3,dwefr,ewre,ewrt#egyfrhgt.com,$2y$08$s2XBZvoAvpEqjjhbx8QPw.eSe5TIuJC25XbaFkTskzAKAGi99QWga,\"2016-09-07 09:34:27\",\"2016-09-07 09:34:27\")"},{"RegiterUsers2":"(4,r3t54y6u677i,retrytyu,etyru#dddj.com,$2y$08$Xb0Xm4KwdSwcBSHX0F6ETOWU60X.NO5D7\/uwVv\/xUAXTUS8LSPCLu,\"2016-09-07 09:46:26\",\"2016-09-07 09:46:26\")"},{"RegiterUsers2":"(5,r3t45y6u,ertrh,435t4y65#sss.com,$2y$08$36DLu49nZ2YOWtU.c625meiyi3\/fmsHxiTuxIU9z9UcyrbIpFSKKW,\"2016-09-07 10:02:05\",\"2016-09-07 10:02:05\")"},{"RegiterUsers2":"(6,ewrtryuyj,ryt,wrewtey#sssks.com,$2y$08$GULHtX3GGXPGgm8gA9yDbeawZlQ5QwD2TX7nrCvEU4j7jrSgPWAQO,\"2016-09-07 10:04:17\",\"2016-09-07 10:04:17\")"},{"RegiterUsers2":"(7,chandu,chandu,ch1235hdhd#dhdjd.com,$2y$08$gpAhcl\/Sg.lGvb.zk.I\/m.PfcttGI6OPFMsMxQVm15dYOtQDvIWSG,\"2016-09-07 10:06:18\",\"2016-09-07 10:06:18\")"},{"RegiterUsers2":"(8,dewfergt,erwrgf,fgf#dgrf.com,$2y$08$ikYAXV1prZsEj2MPxXM4S.Tqn160Jv25cFOQLghK8ptFiSBaIFGZO,\"2016-09-07 10:07:20\",\"2016-09-07 10:07:20\")"},{"RegiterUsers2":"(9,rteryt,wrwter,wretr#gjjd.com,$2y$08$pkOUBl1NlNdBShNWiklya.0zlPzPrEH2edCfvdCiHLnj80GY1sdtm,\"2016-09-08 07:11:46\",\"2016-09-08 07:11:46\")"},{"RegiterUsers2":"(10,Raghu,raghu,raghu#gdgdjd.com,$2y$08$m9wke.vvTTZytYw91I4\/q.qxKoCobLOW7dbCvs66xFyJyy2R9phni,\"2016-09-10 10:06:40\",\"2016-09-10 10:06:40\")"},{"RegiterUsers2":"(11,wewert,ewretr,ewrtey#vsss.com,$2y$08$IXD0eXYTPPGE1MfALonEFey0lr\/KBMZ0.3AIO3sWVgu7IZdWhXwTG,\"2016-09-12 07:48:58\",\"2016-09-12 07:48:58\")"}]
I need like this
{"id":1,
"name":"Chris Sevilleja",
"username":"sevilayha",
"email":"chris#scotch.io",
"password":"$2y$08$i\/ATa68ierqRL47ZxHX4EesJGEcdtKPckZs8GDGpYS.IR4aaQn",
"created_at":"2016-09-07 09:32:41",
"updated_at":"2016-09-07 09:32:41"},
so what is wrong with postgres function and how can I get like above one.

When you call a function returning many columns and you want each one, you must call in the form of:
SELECT col1, col2, ... FROM function(...)
Or:
SELECT * FROM function(...)
So in your case you simple want:
$allUserData=DB::select('SELECT * FROM public."RegiterUsers2"()')

Related

Why am I getting error 17410 end of data on my rest api when I add a parameter to the query

I have ORDS 21 installed in a local 19c oracle database. I have created a stored procedure to list all the departments from the dept table with a cursor that lists the employees from the emp table. If I just list all departments and their employees the api works fine, but if I add a parameter to the query to specify which department, I get an error 17410 no data left .
Both queries are backed by plsql stored procedures. I have created many stored procedures using this same format with parameters and nested cursors before without a problem.
MWE for query that works:
create or replace procedure get_dept
as
l_cur sys_refcursor;
begin
open l_cur for
select d.deptno,d.dname,
cursor (select e.empno,e.ename
from emp e
where e.deptno = d.deptno
order by e.deptno,e.empno
) as employees
from dept d
order by d.deptno;
-- return the resultset in json format
apex_json.open_object;
apex_json.write('emps',l_cur);
apex_json.close_object;
end get_dept;
/
MWE for query that does not work:
create or replace procedure get_dept1
(
p_dept_no in varchar2
) as
l_cur sys_refcursor;
begin
open l_cur for
select d.deptno,d.dname,
cursor (select e.empno,e.ename
from emp e
where e.deptno = d.deptno
order by e.deptno,e.empno
) as employees
from dept d
where d.deptno = to_number(p_dept_no)
order by d.deptno;
-- return the resultset in json format
apex_json.open_object;
apex_json.write('emps',l_cur);
apex_json.close_object;
end get_dept1;
/

Tracking SQL functions in Hasura

Basically I'm trying to compare two JSONB rows and return a numeric value. But I wanna be able to query for it. I'm not sure whether I should use a custom SQL function, a calculated field, or a Postgres generated column, so I need a bit of advice.
I have a jsonb column for each user that keeps a few hundreds of keys/values as such:
USERS TABLE:
| username | user_jsonb_column |
|-----------------------------------------------------------|
| 'user1' | {"key1":"value1", "key2":"value2" ... } |
|--------------|--------------------------------------------|
| 'user2' | {"key2":"value2", "key3":"value3" ... } |
I am trying to calculate the similarity of the jsonb rows of 2 users with a very simple SQL query as such:
SELECT ROUND ((
SELECT COUNT(*) from (
SELECT jsonb_each(user_jsonb_column)
FROM users WHERE username = 'johndoe'
INTERSECT
SELECT jsonb_each(user_jsonb_column)
FROM users WHERE username = 'janedoe'
)::decimal AS SAME_PAIRS
/ --divide it by
SELECT COUNT(*) from (
SELECT jsonb_object_keys(user_jsonb_column)
FROM users WHERE username = 'johndoe'
INTERSECT
SELECT jsonb_object_keys(user_jsonb_column)
FROM users WHERE username = 'janedoe'
) as SAME_KEYS
) * 100) as similarity_percentage
This is working as intended and gives me the similarity result between 2 json objects as a percentage.
I am trying to turn this into a function so that I can query for the similarity percentage of 2 users as such:
query {
calculate_similarity_percentage(
args: {user1: "johndoe", user2: "janedoe"}
){
similarity_percentage_value
}
}
But I'm stuck at this point because I'm not sure whether I should think in terms of a trackable custom SQL function (which should return SETOF <TABLE> but I need a numeric value), a computed field (which can also return BASE type), or maybe a Postgres generated column in my situation.
I've been reading https://hasura.io/docs/1.0/graphql/core/schema/custom-functions.html and https://hasura.io/docs/1.0/graphql/core/schema/computed-fields.html but I couldn't quite figure out how to approach this, so any kind of help or comment would be appreciated.
Update: Yes, as Laurenz Albe pointed out, I am able to create a function like this:
CREATE OR REPLACE FUNCTION public.calculate_similarity_percentage(text, text)
RETURNS numeric
LANGUAGE sql
STABLE
AS $function$
SELECT ROUND(
(select count(*) from (
SELECT jsonb_each(user_jsonb_column) FROM users WHERE username = $1
INTERSECT
SELECT jsonb_each(user_jsonb_column) FROM users WHERE username = $2
) as SAME_PAIRS
)::decimal / (
select count(*) from (
SELECT jsonb_object_keys(user_jsonb_column) FROM users WHERE username = $1
INTERSECT
SELECT jsonb_object_keys(user_jsonb_column) FROM users WHERE username = $2
) as SAME_KEYS
)
* 100) as similarity_percentage
$function$
Then I can execute this function:
SELECT calculate_similarity_percentage('johndoe','janedoe')
And it returns this without any problem:
similarity_percentage
62
However, I would like Hasura to track this function so that I can query it on graphQL as:
query MyQuery {
calculate_similarity_percentage(args: {user1: "johndoe", user2: "janedoe"}) {
similarity_percentage
}
}
But if I try to track the function above, Hasura says:
**SQL Execution Failed**
in function "calculate_similarity_percentage":
the function "calculate_similarity_percentage" cannot be tracked for the following reasons:
• the function does not return a "COMPOSITE" type
• the function does not return a SETOF
• the function does not return a SETOF table
I have no idea if I can find a workaround and return a numeric value as a "COMPOSITE" or SETOF table.
Here is how I kind of solved my case. But this was not the optimal solution so I'm not accepting this as an answer.
I ended up creating another table like this:
USER_RELATION_TABLE:
| user1_col | user2_col |
|--------------------------|
| 'johndoe' | 'janedoe' |
|--------------------------|
| 'brad' | 'angelina' |
|--------------------------|
| ... | ... |
Then I added a computed field on the relation table with the following function:
CREATE OR REPLACE FUNCTION public.calculate_similarity_percentage(user_relation_row user_relation_table)
RETURNS numeric
LANGUAGE sql
STABLE
AS $function$
SELECT ROUND(
(select count(*) from (
SELECT jsonb_each(user_jsonb_column) FROM users
WHERE username = user_relation_row.user1_col
INTERSECT
SELECT jsonb_each(user_jsonb_column) FROM users
WHERE username = user_relation_row.user2_col
) as SAME_PAIRS
)::decimal / (
select count(*) from (
SELECT jsonb_object_keys(user_jsonb_column) FROM users
WHERE username = user_relation_row.user1_col
INTERSECT
SELECT jsonb_object_keys(user_jsonb_column) FROM users
WHERE username = user_relation_row.user2_col
) as SAME_KEYS
)
* 100) as similarity_percentage
$function$
Now I can query it on the graphQL like this:
query MyQuery {
user_relation_table {
similarity
}
}

PostgreSQL ERROR: invalid input syntax for integer: "1e+06"

The full error message is:
ERROR: invalid input syntax for integer: "1e+06"
SQL state: 22P02
Context: In PL/R function sample
The query I'm using is:
WITH a as
(
SELECT a.tract_id_alias,
array_agg(a.pgid ORDER BY a.pgid) as pgids,
array_agg(a.sample_weight_geo ORDER BY a.pgid) as block_weights
FROM results_20161109.block_microdata_res_joined a
WHERE a.tract_id_alias in (66772, 66773, 66785, 66802, 66805, 66806, 66813)
AND a.bldg_count_res > 0
GROUP BY a.tract_id_alias
)
SELECT NULL::INTEGER agent_id,
a.tract_id_alias,
b.year,
unnest(shared.sample(a.pgids,
b.n_agents,
1 * b.year,
True,
a.block_weights)
) as pgid
FROM a
LEFT JOIN results_20161109.initial_agent_count_by_tract_res_11 b
ON a.tract_id_alias = b.tract_id_alias
ORDER BY b.year, a.tract_id_alias, pgid;
And the shared.sample function I'm using is:
CREATE OR REPLACE FUNCTION shared.sample(ids bigint[], size integer, seed integer DEFAULT 1, with_replacement boolean DEFAULT false, probabilities numeric[] DEFAULT NULL::numeric[])
RETURNS integer[] AS
$BODY$
set.seed(seed)
if (length(ids) == 1) {
s = rep(ids,size)
} else {
s = sample(ids,size, with_replacement,probabilities)
}
return(s)
$BODY$
LANGUAGE plr VOLATILE
COST 100;
ALTER FUNCTION shared.sample(bigint[], integer, integer, boolean, numeric[])
OWNER TO "server-superusers";
I'm pretty new to this stuff, so any help would be appreciated.
Not a problem of the function. Like the error messages says: The string '1e+06' cannot be cast to integer.
Obviously, the columns n_agents in your table results_20161109.initial_agent_count_by_tract_res_11 is not an integer column. Probably type text or varchar? (That info would help in your question.)
Either way, the assignment cast does not work for the target type integer. But it does for numeric:
Does not work:
SELECT '1e+06'::text::int; -- error as in question
Works:
SELECT '1e+06'::text::numeric::int;
If my assumptions hold, you can use this as stepping stone.
Replace b.n_agents in your query with b.n_agents::numeric::int.
It's your responsibility that numbers stay in integer range, or you get the next exception.
If that did not nail it, you need to look into function overloading:
Is there a way to disable function overloading in Postgres
And function type resolution:
PostgreSQL function call
The schema search path is relevant in many related cases, but you did schema-qualify all objects, so we can rule that out.
How does the search_path influence identifier resolution and the "current schema"
Your query generally looks good. I had a look and only found minor improvements:
SELECT NULL::int AS agent_id -- never omit the AS keyword for column alias
, a.tract_id_alias
, b.year
, s.pgid
FROM (
SELECT tract_id_alias
, array_agg(pgid) AS pgids
, array_agg(sample_weight_geo) AS block_weights
FROM ( -- use a subquery, cheaper than CTE
SELECT tract_id_alias
, pgid
, sample_weight_geo
FROM results_20161109.block_microdata_res_joined
WHERE tract_id_alias IN (66772, 66773, 66785, 66802, 66805, 66806, 66813)
AND bldg_count_res > 0
ORDER BY pgid -- sort once in a subquery. cheaper.
) sub
GROUP BY 1
) a
LEFT JOIN results_20161109.initial_agent_count_by_tract_res_11 b USING (tract_id_alias)
LEFT JOIN LATERAL
unnest(shared.sample(a.pgids
, b.n_agents
, b.year -- why "1 * b.year"?
, true
, a.block_weights)) s(pgid) ON true
ORDER BY b.year, a.tract_id_alias, s.pgid;

Getting a value from stored procedure within a stored procedure

I have a stored procedure which returns an XML file. At the moment some calculations are done in XSL but I would like to do these within the database using another stored procedure. (adding the result of that calculation to the XML)
ALTER PROCEDURE [dbo].[app_Get_Phone_And_Tariffs]
-- Add the parameters for the stored procedure here
#phone nvarchar(150)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT
PB.UID as '#phoneid',
PB.Short_Title as '#title',
PB.Description as '#desc',
PB.Camera as '#camera',
PB.Storage as '#storage',
PB.Screen_Size as '#screensize',
PB.OS as '#os',
PB.Processor as '#chip',
PB.Image1 as '#image',
PB.Trade_Price as '#tradeprice',
(SELECT
TB.UID as '#tariffid',
TB.Tariff_Name as '#name',
TB.Carrier as '#network',
TB.Inclusive_Minutes as '#mins',
TB.Inclusive_Texts as '#texts',
TB.Inclusive_Data as '#data',
TB.Monthly_Cost as '#monthly',
TB.Commission as '#comm',
(TB.Commission - PB.Trade_Price) as '#upfront'
FROM dbo.Tariff_Base TB
WHERE TB.Active = 1 AND TB.Type = 1
FOR XML PATH('tariff'), TYPE
),
(SELECT
OP.GP_Margin as '#gpmargin'
FROM dbo.Options OP
FOR XML PATH('options'), TYPE
)
FROM dbo.Phone_Base PB
WHERE PB.Friendly_URL_Name = #phone AND PB.Active = 1
FOR XML PATH('detail'), TYPE
END
What I want to do is:
In the inner select (TB) is to call another SP lets call it "calculate" passing 2 variables (TB.Commission and PB.Trade_Price) for the sum
Calculate will return a value i.e. #hp to the stored procedure which can be added/used in the XML List.
Can this be done in SQL Server 2014/T-SQL?
No. But you could do it with a function. See the MSDN documentation, especially example A.
Something like this (untested):
CREATE FUNCTION dbo.Calculate (#Comission float, #TradePrice float)
RETURNS float
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE #SumVal float;
SET #SumVal = #Commission + # TradeValue;
RETURN(#SumVal);
END;
GO
--In your sub-query
SELECT values, dbo.Calculate(TB.Commission, PB.Trade_Price) AS A_Sum
FROM ...;

Comparing two fileds in select command

I am trying to select all records from Transaction_Table where Tr_Amount = Instrument_Number using following Code
Select * from Transaction_Table
where abs(Tr_Amount) = Cast(Instrument_number as INTEGER)
However there are some rows in the table where Instrument_Number is Alphanumeric instead of Just Numeric Data. I there a way to skip the alphanumeric instances in Instrument_Number field in the command.
Switch to TO_NUMBER, which returns NULL for bad data:
Select * from Transaction_Table
where abs(Tr_Amount) = TO_NUMBER(Instrument_number)
TD15.10 implements a TRYCAST:
Select * from Transaction_Table
where abs(Tr_Amount) = TRY_CAST(Instrument_number as INTEGER)