Executing an insert query on successful deletion in postgres - sql

Is it possible to insert some data into one table if some entry is deleted in another table?
I am able to do that with multiple queries(delete first, then insert by checking if it exists). But this runs as two queries. Is it possible to merge the queries or what is the most efficient way of doing this?

WITH deleted_rows AS (
DELETE FROM users
WHERE
id = 15
RETURNING *
)
INSERT INTO users_history (SELECT * FROM deleted_rows);

I explain my answer:
RETURNING * return table records such as select * from command, but return only deleted records. This RETURNING command you can use after the INSERT or UPDATE command too. The WITH query being CTE (Common Table Expression) query, is particularly useful when the subquery is executed multiple times. It is equally helpful in place of temporary tables. It computes the aggregation once and allows us to reference it by its name (maybe multiple times) in the queries. So finally we use SELECT * FROM deleted_rows query which will return all deleted records and using INSERT INTO users_history query we can insert all these return records to the new user_history table.

Related

Is there a way to make a SELECT in BigQuery query conditionally only if a table exists?

I have an app that has to query hundreds of BigQuery tables (in a Dataflow job) , some of which may not exist (there are tables named by day for events which occur on each day, and some days some tables may not have been created).
Is there a way to write a BQ SQL query such that it makes a SELECT against some_table if and only if the named table exists, and returns no rows otherwise?
Someone had posted a query which returns if a table exists
#standardSQL
SELECT COUNT(1) AS table_count
FROM `my-project:blah.__TABLES_SUMMARY__`
WHERE table_id = 'some-table-name-2017-04-02'
But we are trying to do a job in Dataflow, and its difficult to make these queries first outside of the dataflow control structure.
Is there a way to combine something like the query above with a SELECT against that table 'some-table-name-2017-04-02', in a single SQL statement such that if the table does not exist, we just get no rows back, rather than an error?
The problem is that the BigQuery SQL parser will not even compile a query if it references a table name that does not exist, even if no query is done to that table.
Here you can check budd
if not exists
(select * from sysobjects where name="my table")
begin
execute "create table mytable(x int)"
end

PostgreSQL return select results AND add them to temporary table?

I want to select a set of rows and return them to the client, but I would also like to insert just the primary keys (integer id) from the result set into a temporary table for use in later joins in the same transaction.
This is for sync, where subsequent queries tend to involve a join on the results from earlier queries.
What's the most efficient way to do this?
I'm reticent to execute the query twice, although it may well be fast if it was added to the query cache. An alternative is store the entire result set into the temporary table and then select from the temporary afterward. That also seems wasteful (I only need the integer id in the temp table.) I'd be happy if there was a SELECT INTO TEMP that also returned the results.
Currently the technique used is construct an array of the integer ids in the client side and use that in subsequent queries with IN. I'm hoping for something more efficient.
I'm guessing it could be done with stored procedures? But is there a way without that?
I think you can do this with a Postgres feature that allows data modification steps in CTEs. The more typical reason to use this feature is, say, to delete records for a table and then insert them into a log table. However, it can be adapted to this purpose. Here is one possible method (I don't have Postgres on hand to test this):
with q as (
<your query here>
),
t as (
insert into temptable(pk)
select pk
from q
)
select *
from q;
Usually, you use the returning clause with the data modification queries in order to capture the data being modified.

Insert into combined with select where

Let's say we have a query like this (my actual query is similar to this but pretty long)
insert into t1(id1,c1,c2)
select id1,c1,c2 from t2
where not exists(select * from t1 where t1.id1=t2.id1-1)
Does this query select first and insert all, or insert each selected item one by one?
it matters because I'm trying insert a record depending on the previous inserted records and it doesn't seem to work.
First the select query is ran. So it will select all the rows that match your filter. After that the insert is performed. There is not row by row insertion when you use one operation.
Still if you want to do something recursive that will check after each insert you can use CTEs (Common Table Expressions). http://msdn.microsoft.com/en-us/library/ms190766(v=sql.105).aspx
This runs a select statement one time and then inserts based on that. It is much more efficient that way.
Since you already know what you will be inserting, you should be able to handle this in your select query rather than looking at what you have already inserted.

Hive queries using partitioned columns does not retrieve all the records. Why?

I have a Hive statement as below:
INSERT INTO TABLE myTable partioned (myDate) SELECT * from myOthertable
myOthertable contains 1 million records and, while executing the above Insert, not all rows are inserted into myTable. As it is a SELECT * query without any WHERE clause ideally the Insert should be done for all the rows from myOthertable into myTable. It ignores some of the rows while inserting.
Can anyone suggest why this is happening?
The issue may be due to ,If the table is large enough the above query wont work seems like due to the larger number of files created on initial map task.
So in that cases group the records in your hive query on the map process and process them on the reduce side. You can implement the same in your hive query itself with the usage of DISTRIBUTE BY. Below is the query .
FROM myOthertable
INSERT OVERWRITE TABLE myTable(myDate)
SELECT other1, other2 DISTRIBUTE BY myDate;
This link may help

Delete rows from CTE in SQL SERVER

I have a CTE which is a select statement on a table. Now if I delete 1 row from the CTE, will it delete that row from my base table?
Also is it the same case if I have a temp table instead of CTE?
Checking the DELETE statement documentation, yes, you can use a CTE to delete from and it will affect the underlying table. Similarly for UPDATE statements...
Also is it the same case if I have a temp table instead of CTE?
No, deletion from a temp table will affect the temp table only -- there's no connection to the table(s) the data came from, a temp table is a stand alone object.
You can think of CTE as a subquery, it doesn't have a temp table underneath.
So, if you run delete statement against your CTE you will delete rows from the table. Of course if SQL can infer which table to upadte/delete base on your CTE. Otherwise you'll see an error.
If you use temp table, and you delete rows from it, then the source table will not be affected, as temp table and original table don't have any correlation.
In the cases where you have a sub query say joining multiple tables and you need to use this in multiple places then both cte and temp table can be used. If you however want to delete records based on the sub query condition then cte is the way to go. Sometimes you can simply use the delete statement with out a need of cte since it's a delete statement and only rows that satisfy the query conditions get deleted even though multiple conditions are used for filtering.