Manipulate & use the results of UPDATE .... RETURNING - postgresql

Here is a simple PostgreSQL update returning some data:
UPDATE table set num = num + 1
WHERE condition = true
RETURNING table.id, table.num
Is there a way to further use the returned results, as if they came from a select statement? Something like this:
INSERT into stats
(id, completed)
SELECT c.id, TRUE
FROM
(
UPDATE table set num = num + 1
WHERE condition = true
RETURNING table.id, table.num
) c
where c.num > 5
Or do I have to save the returned results into my application, then create a new query out of the returned results?

As of version 9.1, you can use an UPDATE ... RETURNING in a "Common Table Expression" ("CTE"), which for most purposes can be thought of as a named sub-query.
So for your purposes, you could use something like this:
WITH update_result AS
(
UPDATE table set num = num + 1
WHERE condition = true
RETURNING table.id, table.num
)
INSERT into stats
(id, completed)
SELECT c.id, TRUE
FROM update_result as c
WHERE c.num > 5
If you're using a version of Postgres below 9.1, then I think you will have to grab the result into a variable in some procedural code - either your application, or a database function (probably written in PL/pgSQL).

That syntax won't work (unfortunately! that would be convenient).
Either you update and then create another query, or you do everything in a stored procedure where you can safely store and handle query resuts, so that you just have one single database call from your application.

Related

postgresql UPDATE and RETURNING query not returning latest value

I have the following table
p_id, j_id, completed
a b false
c b true
and am using the following query to update the complete to true
update progress_status set completed = true where p_id = 'c' returning (
select to_json(t) from (select count(*) as total, sum(case when "completed" = true then 1 else 0 end) as completed from progress_status where j_id='b') t
) as status
but the query always returns the pre existing value before the update query was executed.
In the above case I would get completed as 1 and total as 2 whereas I expected it to be
completed = 2 total = 2
What is the reason behind this and how can I avoid such a response? Also is there a performance benefit to executing these two queries in the same query or it doesn't really make a difference in performance ?
Try this:
WITH updated AS (UPDATE ... RETURNING list of columns)
SELECT your select query FROM updated;
This should make the SELECT operate on what the UPDATE returns, not on the table itself.

Cannot access temp table in dynamic TSQL

I am creating a temporary table in some dynamic SQL. But when I call it it throws an "Invalid object name '#Settlement_Data_Grouped'" error.
I am assuming it's because dynamic SQL uses it's own seperate instance? So that it is dropped and not available to the outside SQL? It works when I use ##Settlement_Data_Grouped or create a table. But this doesn't help when multiple people are calling the sproc.
I'm thinking I could check if the table exists but that would mean I would have to delete contents and different users may require different outputs which would mean it would not work.
So does anyone have a solution/suggestion I can use where multiple people can be calling the same sproc?
IMHO you do not need the Dynamic SQL. You can change your code like something below and that will give you same result as you are trying to accomplish. Please check for any syntax error if any. I would have provided you full query but in your question you have screenshot instead of the code. So here it goes.
If you want to use Temp Tables:
SELECT
......
INTO #Settlement_Data_Grouped
FROM #Settlement_Data
WHERE (Payment_Date < Settlement_Date AND #outputType = 1) ---This will be true when you have #outputType = 1
OR #outputType = 0 ---This will be true when you have #outputType = 0
GROUP BY Part_No
,NAME
,Order_No
,Invoice_No
-------------
SELECT
......
FROM #Settlement_Data_Grouped
If you want to use CTE:
WITH Settlement_Data_Grouped
AS (
SELECT
......
FROM #Settlement_Data
WHERE (Payment_Date < Settlement_Date AND #outputType = 1) ---This will be true when you have #outputType = 1
OR #outputType = 0 ---This will be ture when you have #outputType = 0
GROUP BY Part_No
,NAME
,Order_No
,Invoice_No
)
SELECT
......
FROM Settlement_Data_Grouped
The problem is that the temp table only exists within the scope of the dynamic SQL execution context. The way around it would be to create the temp table outside of the dynamic SQL and then insert into it:
CREATE TABLE #Settlement_Data_Grouped (PartNo varchar(50) ......)
INSERT INTO #Settlement_Data_Grouped
EXEC(#selectSQL)

Postgres Update Using Select Passing In Parent Variable

I need to update a few thousand rows in my Postgres table using the result of a array_agg and spatial lookup.
The query needs to take the geometry of the parent table, and return an array of the matching row IDs in the other table. It may return no IDs or potentially 2-3 IDs.
I've tried to use an UPDATE FROM but I can't seem to pass into the subquery the parent table geom column for the SELECT. I can't see any way of doing a JOIN between the 2 tables.
Here is what I currently have:
UPDATE lrc_wales_data.records
SET lrc_array = subquery.lrc_array
FROM (
SELECT array_agg(wales_lrcs.gid) AS lrc_array
FROM layers.wales_lrcs
WHERE st_dwithin(records.geom_poly, wales_lrcs.geom, 0)
) AS subquery
WHERE records.lrc = 'nrw';
The error I get is:
ERROR: invalid reference to FROM-clause entry for table "records"
LINE 7: WHERE st_dwithin(records.geom_poly, wales_lrcs.geom, 0)
Is this even possible?
Many thanks,
Steve
Realised there was no need to use SET FROM. I could just use a sub query directly in the SET:
UPDATE lrc_wales_data.records
SET lrc_array = (
SELECT array_agg(wales_lrcs.gid) AS lrc
FROM layers.wales_lrcs
WHERE st_dwithin(records.geom_poly, wales_lrcs.geom, 0)
)
WHERE records.lrc = 'nrw';

Execute storedprocedure that return 0 with entitiy-framework

I have a stored procedure in my db that looks like this:
IF EXISTS (SELECT * FROM Table1)
BEGIN
-- select statement
END
I am using this procedure to check if there is any data inside table1. Table1 is used as a queue on database side.
In my C# application I am using the entity framework to execute this stored procedure. Method Looks like this:
using (DatabaseEntities db = new DatabaseEntities())
{
var result = db.ALL_GET_JOBS();
if (result == null)
{
Console.WriteLine("No new jobs");
}
else
{
Console.WriteLine(string.Format("received {0} new jobs", result.Count()));
}
}
When I execute to procedure I get an exception telling me that one of my defined columns doesn't exists within the result. Yeah, because the procedure is returning 0. The exception is thrown before I reach the if statement.
I already tried adding .DefaultIfEmpty(null) or .FirstOrDefault() to the call of the procedure, but as far as I can say, the error occurs during the evaluation of the result.
Does any one of you have an idea how to handle a procedure that is returning 0 instead of a result set in entity Framework?
bg
Christoph
I think you should change your sp or create a new one with Count function:
SELECT Count(*) FROM Table1
with this your resul is always a number (0 or greater).
I konw it's a workaround, but have you tried having the stored procedure always return the same?
Something like:
SELECT Field1, Field2 FROM Table1
You can just check if result.Count() == 0 instead of result == null.

PostgreSQL and pl/pgsql SYNTAX to update fields based on SELECT and FUNCTION (while loop, DISTINCT COUNT)

I have a large database, that I want to do some logic to update new fields.
The primary key is id for the table harvard_assignees
The LOGIC GOES LIKE THIS
Select all of the records based on id
For each record (WHILE), if (state is NOT NULL && country is NULL), update country_out = "US" ELSE update country_out=country
I see step 1 as a PostgreSQL query and step 2 as a function. Just trying to figure out the easiest way to implement natively with the exact syntax.
====
The second function is a little more interesting, requiring (I believe) DISTINCT:
Find all DISTINCT foreign_keys (a bivariate key of pat_type,patent)
Count Records that contain that value (e.g., n=3 records have fkey "D","388585")
Update those 3 records to identify percent as 1/n (e.g., UPDATE 3 records, set percent = 1/3)
For the first one:
UPDATE
harvard_assignees
SET
country_out = (CASE
WHEN (state is NOT NULL AND country is NULL) THEN 'US'
ELSE country
END);
At first it had condition "id = ..." but I removed that because I believe you actually want to update all records.
And for the second one:
UPDATE
example_table
SET
percent = (SELECT 1/cnt FROM (SELECT count(*) AS cnt FROM example_table AS x WHERE x.fn_key_1 = example_table.fn_key_1 AND x.fn_key_2 = example_table.fn_key_2) AS tmp WHERE cnt > 0)
That one will be kind of slow though.
I'm thinking on a solution based on window functions, you may want to explore those too.