Related
I am a newbie to PostgreSQL. I have the below function and it is giving me an error. basically, I am passing JSON as a parameter to the function, extracting values, and inserting it into 2 tables. it is one to many relationships. so based on that one invoice has multiple line items:
PostgreSQL function:
-- FUNCTION: public.insertorupdateinvoice(jsonb)
-- DROP FUNCTION IF EXISTS public.insertorupdateinvoice(jsonb);
CREATE OR REPLACE FUNCTION public.insertorupdateinvoice(
invoice jsonb)
RETURNS void
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
AS $BODY$
Declare _invoiceid bigint;
begin
insert into invoicemaster (expenseid, invoiceno, transactiondate, totalinvoiceamount, invoicedoc, createdby, createdon)
select (j.invoice->>'expenseid')::bigint,
j.invoice->>'invoiceno'::character,
(j.invoice->>'transactiondate')::date,
(j.invoice->>'totalinvoiceamount')::double precision,
j.invoice->>'invoicedoc'::character,
(j.invoice->>'createdby')::bigint,
NOW()
from jsonb_array_elements(invoice) as j(invoice)
returning invoiceid into _invoiceid;
insert into lineitemmaster (invoiceid, transactiondate, merchantname, amount, departmentid, policyid, itemdescription,
itemcategory, itemtype, status, isrejected, createdby, createdon)
select _invoiceid::bigint,
(x.invoice->>'transactiondate')::date,
x.invoice->>'merchantname',
(x.invoice->>'amount')::double precision,
(x.invoice->>'departmentid')::integer,
(x.invoice->>'policyid')::integer,
x.invoice->>'itemdescription',
(x.invoice->>'itemcategory')::integer,
(x.invoice->>'itemtype')::integer,
(x.invoice->>'status')::boolean,
(x.invoice->>'isrejected')::boolean,
(x.invoice->>'createdby')::bigint,
NOW()
from jsonb_array_elements(invoice ->'lineitems') as x;
end;
$BODY$;
ALTER FUNCTION public.insertorupdateinvoice(jsonb)
OWNER TO postgres;
calling function as :
select * from insertorupdateinvoice('{"expenseid":1,
"invoiceno":"04012022",
"transactiondate":"2022-01-04",
"totalinvoiceamount":1000.00,
"invoicedoc":"invoicedoc",
"createdby":1,
"lineitems":[
{"transactiondate":"2022-01-01", "merchantname":"Apple", "amount":"100.50", "departmentid":"1","policyid":"1", "itemdescription":"iphone 14 pro max", "itemcategory":"55", "itemtype":"499", "status":"true", "isrejected":"false", "createdby":"1"},
{"transactiondate":"2022-01-02", "merchantname":"Samsung", "amount":"1050.35", "departmentid":"2","policyid":"2", "itemdescription":"samsung galaxy tab", "itemcategory":"40", "itemtype":"50", "status":"true", "isrejected":"false", "createdby":"1"},
{"transactiondate":"2022-01-03", "merchantname":"Big bazar", "amount":"555.75", "departmentid":"3","policyid":"3", "itemdescription":"grocerry", "itemcategory":"5", "itemtype":"90", "status":"false", "isrejected":"false", "createdby":"1"}
]}');
getting error as below:
ERROR: cannot extract elements from an object
CONTEXT: SQL statement "insert into invoicemaster (expenseid, invoiceno, transactiondate, totalinvoiceamount, invoicedoc, createdby, createdon)
select (j.invoice->>'expenseid')::bigint,
j.invoice->>'invoiceno'::character,
(j.invoice->>'transactiondate')::date,
(j.invoice->>'totalinvoiceamount')::double precision,
j.invoice->>'invoicedoc'::character,
(j.invoice->>'createdby')::bigint,
NOW()
from jsonb_array_elements(invoice) as j(invoice)
returning invoiceid"
PL/pgSQL function insertorupdateinvoice(jsonb) line 5 at SQL statement
SQL state: 22023
Thanks
try this :
CREATE OR REPLACE FUNCTION public.insertorupdateinvoice(
invoice jsonb)
RETURNS void
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
AS $BODY$
Declare _invoiceid bigint;
begin
insert into invoicemaster (expenseid, invoiceno, transactiondate, totalinvoiceamount, invoicedoc, createdby, createdon)
values ( (invoice->>'expenseid') :: bigint,
invoice->>'invoiceno',
(invoice->>'transactiondate') :: date,
(invoice->>'totalinvoiceamount') :: double precision,
invoice->>'invoicedoc',
(invoice->>'createdby') :: bigint,
NOW()
)
returning invoiceid into _invoiceid;
insert into lineitemmaster (invoiceid, transactiondate, merchantname, amount, departmentid, policyid, itemdescription,
itemcategory, itemtype, status, isrejected, createdby, createdon)
select _invoiceid::bigint,
(x->>'transactiondate')::date,
x->>'merchantname',
(x->>'amount')::double precision,
(x->>'departmentid')::integer,
(x->>'policyid')::integer,
x->>'itemdescription',
(x->>'itemcategory')::integer,
(x->>'itemtype')::integer,
(x->>'status')::boolean,
(x->>'isrejected')::boolean,
(x->>'createdby')::bigint,
NOW()
from jsonb_array_elements(invoice ->'lineitems') as x;
end;
$BODY$;
see dbfiddle
There is a table objects, which stores data on real estate objects. Me need to use a query to calculate a new field that will display the date range from Monday to Sunday, which includes the date the object was created (for example, “2020-11-16 - 2020-11-22”)
create table objects(
object_id int NOT NULL PRIMARY KEY ,
city_id int not null ,
price int ,
area_total int ,
status varchar(50) ,
class varchar(50) ,
action varchar(50) ,
date_create timestamp,
FOREIGN KEY(city_id) references avg_price_square_city(city_id)
);
Data in the table:
INSERT INTO objects (object_id, city_id, price, area_total, status, class, action, date_create)
VALUES (1, 1, 4600000, 72, 'active', 'Secondary', 'Sale', '2022-05-12 21:49:34');
INSERT INTO objects (object_id, city_id, price, area_total, status, class, action, date_create)
VALUES (2, 2, 5400000, 84, 'active', 'Secondary', 'Sale', '2022-05-19 21:49:35');
The query should display two fields: the object number and a range that includes the date it was created. How can this be done ?
P.S
I wrote this query,but he swears at the "-" sign:
SET #WeekRangeStart ='2022/05/10';
SET #WeekRangeEnd = '2022/05/17';
select object_id,#range := #WeekRangeStart '-' #WeekRangeEnd
FROM objects where #range = #WeekRangeStart and date_create between #WeekRangeStart and #WeekRangeEnd
UNION
select object_id,#range from objects where #`range` = #WeekRangeEnd;
Error:[42000][1064] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '#WeekRangeEnd FROM objects where #range = #WeekRangeStart and date_create betwee' at line 1
I want to receive in query:
object_id #range
1 2022/05/10 - 2022/05/17
The column #range must contain the date from the "date_create"
SET #WeekRangeStart = CAST('2022/05/10' as DATE);
SET #WeekRangeEnd = CAST('2022/05/17' as DATE);
SET #range = CONCAT(#WeekRangeStart,' - ',#WeekRangeEnd) ;
-- select #range;
select
object_id,
#range
FROM objects
where DATE(date_create) between #WeekRangeStart and #WeekRangeEnd
UNION
select object_id,#range from objects
;
Gives next result:
object_id
#range
1
2022-05-10 - 2022-05-17
2
2022-05-10 - 2022-05-17
This result is the output of the SQL part that is put after the UNION. Because date_create is not between your WeekRangeStart and WeekRangeEnd.
You should take some time, and read the UNION documentation.
The variable #range is calculated before the SQL statement, because the value is a constant.
see: DBFIDDLE
NOTE: You should try to use the same dateformat everywhere, and not mix date like '2022-05-19 21:49:35' and 2022/05/10. Use - OR use /, but do not mix them...
EDIT: After the calirification "Me need to use a query to calculate a new field that will display the date range from Monday to Sunday,...":
You probably wanted to do:
SET #WeekDate = CAST('2022/05/10' as DATETIME);
SELECT
ADDDATE(#WeekDate, -(DAYOFWEEK(#WeekDate)-1) +1) as Monday,
DATE_ADD(ADDDATE(#WeekDate, -(DAYOFWEEK(#WeekDate)-1) +9), INTERVAL -1 SECOND) as Sunday;
output:
Monday
Sunday
2022-05-09 00:00:00
2022-05-16 23:59:59
I've got a report that has 6 parameters. All parameters need to be optional and 3 have to be multi-value. One of the optional parameters is a dropdown, the rest are manually keyed in text boxes.
The Where clause below works when there are multiple #VendorNum values and one #FullJA value, but fails with multiple #FullJA values regardless of the #VendorNum count.
Parameters:
#VendorNum - keyed manually by user (space delimited) - optional, can be multivalue
#FullJA - keyed manually by user (space delimited) - optional, can be multivalue
#BU - optional, can be multivalue - when #JA is populated, this will auto-populate, if #JA isn't populated it's a dropdown with all selected.
#JA3 - keyed by user - optional, single value
#StartDate and #EndDate - optional single values
select * from some_table
WHERE
/*FULL JA*/
(
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND LEFT(JA, 7) IN (#FullJA)
AND BU IN(#BU)
AND #JA3 IS NULL
)
OR
/*DATE RANGE*/
(
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND LEN(ISNULL(CONVERT(VARCHAR(20), Cleared_When), '0')) >= #ClearedOnly
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND BU IN (#BU)
AND #FullJA IS NULL
AND #JA3 IS NULL
)
/*BUS UNIT AND JA3*/
OR (
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND BU IN (#BU)
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND LEFT(JA, 3) = (#JA3)
AND #FullJA IS NULL
)
/*BUS UNIT ONLY*/
OR (
SUBSTRING(VendorNum, PATINDEX('%[^0]%', VendorNum + '.'), LEN(VendorNum)
) IN (#VendorNum)
AND BU IN (#BU)
AND ad.Audit_Publish_Date >= ISNULL(#StartDate, '2015-01-01')
AND ad.Audit_Publish_Date <= ISNULL(#EndDate, '2025-12-31')
AND #JA3 IS NULL
AND #FullJA IS NULL
)
The dataset parameter values for #FullJA and #VendorNum are both
=IIF(InStr(Parameters!FullJA.Value," ")>0,SPLIT(Parameters!FullJA.Value," "),Parameters!FullJA.Value) and all params are set as NOT multivalue, with nulls allowed.
Any help would be greatly appreciated. I've written over 200 reports for this project and this is the only one that is really grinding my gears!
Thanks!
I would approach this by building up some temp tables / table variables, to hold the potentially multi-valued variables, and then joining to those tables. This has the advantage of you being able to insert all possible values, in the case they have omitted the variable. So, you'd split your strings and put them into those tables (something along the lines of this example) if given the variable, and otherwise just do an insert into to populate your temp table / table variable.
For a split function, I prefer something like this:
create FUNCTION [dbo].[Split] (#sep VARCHAR(32), #s VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
(
SELECT r.value('.','VARCHAR(MAX)') as Item
FROM (SELECT CONVERT(XML, N'<root><r>' + REPLACE(REPLACE(REPLACE(#s,'& ','& '),'<','<'), #sep, '</r><r>') + '</r></root>') as valxml) x
CROSS APPLY x.valxml.nodes('//root/r') AS RECORDS(r)
)
GO
GRANT SELECT
ON OBJECT::[dbo].[Split] TO PUBLIC
AS [dbo];
I would then put those variables into a table using something like this (my separator is a ", "):
select ltrim(rtrim(ppl.Item)) as PersonName
into #gppl
from dbo.Split(', ', #PersonListForCompare) as ppl
You would do something more like:
select ltrim(rtrim(vnd.Item)) as VendorNum
into #vendorNums
from dbo.Split(', ', #VendorNum) as vnd
You would then join to that temp table just like any other table & use it to limit your results that way. In your case, you want to put in all vendors (possibly) if they didn't give you any input. So, you'd do something like:
create table #vendorNums (VendorName varchar(64)) --I have no idea, here, what this data looks like
if #VendorNum is not null and datalength(#VendorNum) > 0
insert into into #vendorNums (VendorNum)
select ltrim(rtrim(vnd.Item))
from dbo.Split(', ', #VendorNum) as vnd
else
insert into into #vendorNums (VendorNum)
select VendorNum
from dbo.Vendors
That said, I think that you could use your select from dbo.Split directly as a table in a join, rather than putting it into the temp table. Only problem would be you'd have to be sure you had data in there to split, or else you're going to have a bunch of combinations to get the right match-up of null parameters vs. filled ones.
I want to insert a query into a database which contain single quotes within the value. How can I handle this in PHP?
My query is:
insert into query (date_time, userid, user_traits, query_sql, status, description, is_scheduled_row)
values ('2016-01-06 02:39:01', '307', '0,3598,1937,13891,37746,22082,2596,2431,12850,3917,1234784,44712,14638,14418,12850,2631,25003,11428,27450,2592,23593,11441,2826,36330,32219,32351,20720,13997,2594,2467,15687', 'Select * from gl_base_schema.item where national_status_cd = 'A'', 'in queue', ' (Scheduled Query #413) Pull all items where National Status Code is 'A'', 1);
It shows error as
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'A'', 'in queue', ' (Scheduled Query #413) Pull all items where National Status C' at line 1
Replace your single quote(') in value to BackSlash & Single Quote (\') or two single quotes ('')
Try this:
INSERT INTO QUERY (date_time, userid, user_traits, query_sql, STATUS, description, is_scheduled_row)
VALUES ('2016-01-06 02:39:01', '307', '0,3598,1937,13891,37746,22082,2596,2431,12850,3917,1234784,44712,14638,14418,12850,2631,25003,11428,27450,2592,23593,11441,2826,36330,32219,32351,20720,13997,2594,2467,15687', 'Select * from gl_base_schema.item where national_status_cd = ''A''', 'in queue', ' (Scheduled Query #413) Pull all items where National Status Code is ''A''', 1);
OR
INSERT INTO QUERY (date_time, userid, user_traits, query_sql, STATUS, description, is_scheduled_row)
VALUES ('2016-01-06 02:39:01', '307', '0,3598,1937,13891,37746,22082,2596,2431,12850,3917,1234784,44712,14638,14418,12850,2631,25003,11428,27450,2592,23593,11441,2826,36330,32219,32351,20720,13997,2594,2467,15687', 'Select * from gl_base_schema.item where national_status_cd = \'A\'', 'in queue', ' (Scheduled Query #413) Pull all items where National Status Code is \'A\'', 1);
$query = "Select * from gl_base_schema.item where national_status_cd = 'A'";
$sql = "insert into query (date_time, userid, user_traits, query_sql, status, description, is_scheduled_row) values ('2016-01-06 02:39:01', '307', '0,3598,1937,13891,37746,22082,2596,2431,12850,3917,1234784,44712,14638,14418,12850,2631,25003,11428,27450,2592,23593,11441,2826,36330,32219,32351,20720,13997,2594,2467,15687', '."'".$query."'".', 'in queue', ' (Scheduled Query #413) Pull all items where National Status Code is \'A\'', 1)";
You can use like that with double and single quote combination:
insert into query (date_time, userid, user_traits, query_sql, status, description, is_scheduled_row)
VALUES ("2016-01-06 02:39:01","307","0,3598,1937,13891,37746,22082,2596,2431,12850,3917,1234784,44712,14638,14418,12850,2631,25003,11428,27450,2592,23593,11441,2826,36330,32219,32351,20720,13997,2594,2467,15687","Select * from gl_base_schema.item where national_status_cd = 'A'","in queue"," (Scheduled Query #413) Pull all items where National Status Code is 'A'", 1)
You can use 'A' this string into another string than you can use this as "'A' test"
Where you have 'A'', make it 'A'''. The extra ' escapes the next ', so you need '' for one '. Hope that helps.
SQL statement:
(select top 1 [egrp_name] from [Enotify Group] where [egrp_id] in (a.grp_id) )
e value of a.grp_id is '0,1145' and i am getting error
Conversion failed when converting the varchar value '0,1145' to data type int.
Can anybody tell me how can i change '0,1145' to 0,1145 in above case, so my query does work and also if their is any other way to do this
You can use a split-string function to change your comma delimited string into a table.
select top(1) [egrp_name]
from [Enotify Group]
where [egrp_id] in (
select Value
from dbo.SplitInts(a.grp_id)
);
One version of a split-string function that you can use if you like:
create function dbo.SplitInts(#Values nvarchar(max)) returns table with schemabinding
as
return
(
select T2.X.value(N'.', N'int') as Value
from (select cast(N'<?X '+replace(#Values, N',', N'?><?X ') + N'?>' as xml).query(N'.')) as T1(X)
cross apply T1.X.nodes(N'/processing-instruction("X")') as T2(X)
);
Or you can use like.
select top(1) [egrp_name]
from [Enotify Group]
where ','+a.grp_id +',' like '%,'+cast(egrp_id as varchar(11))+',%' ;