update and select in same query [duplicate] - sql

I need to update some rows of the tables and then display these rows. Is there a way to do this with one single query and avoid this 2 query ? :
UPDATE table SET foo=1 WHERE boo=2
SELECT * from table WHERE ( foo=1 ) AND ( boo=2 )

In PostgreSQL v8.2 and newer you can do this using RETURNING:
UPDATE table
SET foo=1
WHERE boo=2
RETURNING *

You can use a stored procedure in PL/pgSQL. Take a look at the [docs][1]
Something like this
CREATE FUNCTION run(fooVal int, booVal int)
RETURNS TABLE(fooVal int, booVal int)
AS $$
BEGIN
UPDATE table SET foo = fooVal WHERE boo= booVal;
RETURN QUERY SELECT fooVal, booVal from table WHERE ( foo = fooVal ) AND ( boo = booVal );
END;
$$ LANGUAGE plpgsql;
You will save the roundtrip time for sending another statement. This should not be a performance bottleneck. So short answer: Just use two queries. That's fine and this is how you do it in SQL.
[1]: http://www.postgresql.org/docs/8.4/static/plpgsql.html docs

You can use stored procedure or function. It will contains your queries.

Related

Postgresql stored procedure temporary table variable is not a known variable

I've been doing research and trying things out a bunch of different ways, but with no success. I want to create a temporary table and then as I'm doing some searches, fill it up with stuff. I was able to do this with SQL Server by just declaring a table inside the procedure, but with Postgresql I've read I need to create a temporary table specifically.
My strategy started out with just
CREATE TEMP TABLE myTempTable
(
propOne bigint,
propTwo smallint,
createdAtUtc timestamp(6)
);
I even moved it to right after the "BEGIN". Down the file I get this error:
ERROR: "myTempTable" is not a known variable
LINE 77: SELECT * INTO myTempTable from myResult;
Next, I tried to create the temp table when I'm ready to fill it...
WITH some_updated_records AS
(
UPDATE dbTable
SET tablePropertyStatus = 3
WHERE tablePropertyDate < storedProcedurePropertyDate
RETURNING *
)
CREATE TEMP TABLE myTempTable as
(
SELECT *
FROM some_updated_records
);
I still get the same basic error above, but zero errors until it encounters the myTempTable variable.
I'm definitely not a SQL genius (perhaps, eventually, with your help), so there might be some other things I'm doing wrong. My whole task is to convert a SQL Server stored procedure to Postgresql.
What could I being doing wrong to make that temporary table variable un-declared? Is there a special way I need to declare it ahead of time? Am I making a mistake about how to create or declare a temporary table.
Another strategy could be to just keep saving records into a collection of types, forget the "temp table." Is there a way to do this in plpgsql?
UPDATE w/Examples
This version doesn't work. It stops at the create table.
CREATE OR REPLACE PROCEDURE MyTestProcedure(
p_Endpoint Varchar(256),
p_ContentType Varchar(200),
MaxInProcess int = NULL)
LANGUAGE plpgsql
AS $body$
DECLARE
v_UtcNow timestamp(6);
v_ExpiredProcessing timestamp(6);
BEGIN
SELECT CURRENT_TIMESTAMP into v_UtcNow at time zone 'utc';
WITH first_updated AS (UPDATE MyTable
SET Status = 1
WHERE UpdatedAtUtc < v_UtcNow
RETURNING Id, Status, UpdatedAtUtc)
CREATE TEMP TABLE IF NOT EXISTS statustable AS (SELECT Id, Status, UpdatedAtUtc FROM first_updated)
WITH m_result AS (UPDATE MyTable
SET Status = 3,
WHERE ExpirationDateTimeUtc < v_UtcNow
RETURNING Id, Status, UpdatedAtUtc)
INSERT INTO statustable from m_result;
DROP TABLE statustable;
END;
$body$
This errors out at the table creation.
INE 22: CREATE TEMP TABLE statustable as...
The other example would be something similar to creating the table first and then inserting into it. That's probably where I messed up. Working solution will be added in a minute, if someone doesn't add it in first.
You can use a CTE, but put the CTE within the parentheses for the table creation.
CREATE TEMPORARY TABLE myTempTable AS (
WITH cte_updated_records AS (
UPDATE dbTable
SET tablePropertyStatus = 3
WHERE tablePropertyDate < storedProcedurePropertyDate
RETURNING *
)
SELECT * FROM cte_updated_records
);
https://www.postgresql.org/docs/14/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT1
Please refer the Tip section:
Tip Note that this interpretation of SELECT with INTO is quite
different from PostgreSQL's regular SELECT INTO command, wherein the
INTO target is a newly created table. If you want to create a table
from a SELECT result inside a PL/pgSQL function, use the syntax CREATE
TABLE ... AS SELECT.
based on this then you can do
CREATE TEMP TABLE statustable AS (here is your query clause)
Maybe you can do update later.
Another Point is as per manual, seems you cannot do CREATE Table by using CTE.
Each auxiliary statement in a WITH clause can be a SELECT, INSERT,
UPDATE, or DELETE; and the WITH clause itself is attached to a primary
statement that can also be a SELECT, INSERT, UPDATE, or DELETE.
https://www.postgresql.org/docs/current/queries-with.html
LukStorms's answer is pretty neat. But serval steps maybe more readable?
When you're debugging, things can get a little crazy. What happens often, I find, is I try one good solution, but I don't know how to implement it quite right, so the following works. I think I was forgetting the select in the INSERT INTO's.
CREATE OR REPLACE PROCEDURE MyTestProcedure(
p_Endpoint Varchar(256),
p_ContentType Varchar(200),
MaxInProcess int = NULL)
LANGUAGE plpgsql
AS $body$
DECLARE
v_UtcNow timestamp(6);
v_ExpiredProcessing timestamp(6);
BEGIN
SELECT CURRENT_TIMESTAMP into v_UtcNow at time zone 'utc';
CREATE TEMP TABLE status_table(
Id bigint,
Status smallint,
CreatedAtUtc timestamp(6));
WITH first_updated AS (UPDATE MyTable
SET Status = 1
WHERE UpdatedAtUtc < v_UtcNow
RETURNING Id, Status, UpdatedAtUtc)
INSERT INTO status_table
SELECT Id, Status, UpdatedAtUtc
FROM first_updated;
WITH m_result AS (UPDATE MyTable
SET Status = 3
WHERE ExpirationDateTimeUtc < v_UtcNow
RETURNING Id, Status, UpdatedAtUtc)
INSERT INTO status_table
select Id, Status, UpdatedAtUtc
from m_result;
DROP TABLE status_table;
END;
$body$

Postgresql Procedure select into temp table

Being a recent convert from SQL Server, I am getting to know Postgresql a bit.
I really hate having to write nested selevt statements in SQL since I find that the readability and maintainability of the code suffers when I do.
Usually I would create a stored procedure in SQL Server where I would select something into a temporary table, that I can then use in another select statement.
CREATE OR ALTER PROCEDURE Procname
AS
BEGIN
SELECT
Somewhere.Col_1,
Somewhere.Col_2
INTO
#Temptable
FROM
Somewhere Somewhere
SELECT
Temptable.Col_1,
Somewhere_Else.Col3
FROM
#Temptable Temptable
INNER JOIN
Somewhere_Else.Col_2 = Temptable.Col_2
END
When I execute this procedure I would get returned the final select query
How would I replicate this procedure in Postgresql?
I know that you can select into a temporary table, but I cannot seem to figure out how to use this table in the next select statement within the same procedure
Create a set returning function, there is no need for a temp table at all.
CREATE function Procname()
returns table(col_1 ???, col2 ???) --<< change data types here
AS
$$
SELECT
Temptable.Col_1,
Somewhere_Else.Col3
FROM Somewhere Temptable
INNER JOIN Somewhere_Else ON Somewhere_Else.Col_2 = Temptable.Col_2;
$$
language sql
stable;
But for such a simple statement, I would rather create a view.

Function for row insertion

I am relatively newbie with SQL Server, and I have some experience and practices from Oracle & PostgreSQL which i want to use in the SQL Server.
I need to create function which takes fields values for new row in the table and which also returning autogenerated ID value of the new record.
First of all I am faced with the fact that the functions in SQL Server can not change data in the tables. The second my discovery was that is the procedures in SQL Server can return values through return #result construction.
I investigate output mechanism of the DML queries, but they returns not scalar but table results.
Be patient and let me more clear. There is PostgreSQL function which doing what I want:
Table creation script:
create table foobar
(
foo bigint not null default nextval('s_foobar'::regclass),
bar character varying(16),
constraint pk_foobar primary key (foo)
);
and function script:
create or replace function f_foobar_insert(p_bar character varying)
returns integer as
$body$declare
result integer;
begin
insert into foobar(bar) values (p_bar) returning foo into result;
return result;
end;$body$ language plpgsql;
Is there any possibility to make something like this in SQL Server in the same way?
In SQL Server, the table creation would be:
create table foobar
(
foo bigint not null identity primary key,
bar varchar(16)
);
The following is one way in SQL Server to get the functionality:
insert into foobar(bar) select 'value';
select ##identity;
This is not really the preferred way. You should really use the output clause:
declare #t table (foo bigint);
insert into foobar(bar)
output inserted.foo into #t
select 'value';
select foo from #t;
You can wrap this in a stored procedure if you like, but it doesn't seem necessary, and stored procedures have different semantics from functions.

SQL Query using a function to select data

What is the best way of writing an sql query that calls a user defined function as part of the query before produce the selected output. i.e. I want to do something like below please where I the user defined function does some calculations on the table data.
select field1, field2 from table1 where function(table1.field3, table1.field4) > 10
Your (scalar) function:
CREATE FUNCTION my_function (#a AS int, #b AS int)
RETURNS int
BEGIN
RETURN #a * #b
END
Your query:
SELECT field1, field2
FROM table1
WHERE dbo.my_function(table1.field3, table1.field4) > 10
Don't forget the dbo in dbo.my_function. It is required for user defined scalar functions.
Stored procedure may play well or just to write a math/string condition. Depends on how complicated is your condition.

SELECT against stored procedure SQL Server

SELECT Val from storedp_Value within the query editor of SQL Server Management Studio, is this possible?
UPDATE
I tried to create a temp table but it didn't seem to work hence why I asked here.
CREATE TABLE #Result
(
batchno_seq_no int
)
INSERT #Result EXEC storedp_UPDATEBATCH
SELECT * from #Result
DROP TABLE #Result
RETURN
Stored Procedure UpdateBatch
delete from batchno_seq;
insert into batchno_seq default values;
select #batchno_seq= batchno_seq_no from batchno_seq
RETURN #batchno_seq
What am I doing wrong and how do I call it from the query window?
UPDATE #2
Ok, I'd appreciate help on this one, direction or anything - this is what I'm trying to achieve.
select batchno_seq from (delete from batchno_seq;insert into batchno_seq default values;
select * from batchno_seq) BATCHNO
INTO TEMP_DW_EKSTICKER_CLASSIC
This is part of a larger select statement. Any help would be much appreciated. Essentially this SQL is broken as we've migrated for Oracle.
Well, no. To select from a stored procedure you can do the following:
declare #t table (
-- columns that are returned here
);
insert into #t(<column list here>)
exec('storedp_Value');
If you are using the results from a stored procedure in this way and you wrote the stored procedure, seriously consider changing the code to be a view or user defined function. In many cases, you can replace such code with a simpler, better suited construct.
This is not possible in sql server, you can insert the results into a temp table and then further query that
CREATE TABLE #temp ( /* columns */ )
INSERT INTO #temp ( /* columns */ )
EXEC sp_MyStoredProc
SELECT * FROM #temp
WHERE 1=1
DROP TABLE #temp
Or you can use OPENQUERY but this requires setting up a linked server, the SQL is
SELECT * FROM (ThisServer, 'Database.Schema.ProcedureName <params>')
The best article (in my opinion) about all possible methods for sharing data between stored procedures in SQL Server you can find here: http://www.sommarskog.se/share_data.html
Try this
Change 'Return'
delete from batchno_seq;
insert into batchno_seq default values;
select #batchno_seq= batchno_seq_no from batchno_seq
RETURN #batchno_seq
to 'Select'
delete from batchno_seq;
insert into batchno_seq default values;
select #batchno_seq= batchno_seq_no from batchno_seq
SELECT #batchno_seq
My approach
select * into new_table from (select t1.col1,t1.col2,..
from table1 t1
union
select t2.cola,t2.colb,..
from table2 t2) as union_table
I MUST be missing something.
Since your stored procedure does not return a result set, and instead returns an integer, using the RETURN functionality of stored procs, you simply CANNOT INSERT into ANY table (since there isn't any result set coming back, at all).
BUT, you can (assuming that this is done iteratively, and not over a set) simply store the return value into a local variable, and insert that variable's value into whatever table is necessary.
However, if you simply want to return the value in the results of a Query Window in SSMS, doing the INSERT and SELECTING is overkill.
It seems to me like THIS would suffice (in a query window):
DECLARE #RetVal INT = 0;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
EXEC #RetVal = storedp_UPDATEBATCH;
COMMIT TRANSACTION;
SELECT #RetVal;
--OR
--PRINT #RetVal;
If this is way far off base, please provide the DDL for "batchno_seq", maybe I can be of better assistance that way.
Cheers!