Insert into combined with select where - sql

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.

Related

Executing an insert query on successful deletion in postgres

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.

Remove the duplicates expect one record in SQL Server

Here I wanted to delete all records with value 1 and only keep a single record
Without knowing your DBMS it's really tough to know which query you need. If your dbms supports cte and row_number() then below query will work.
with cte as
(select *,row_number()over(order by column_1)rn from table_name)t
delete cte where rn>1
In SQL Server this will work fine.
Given the nature of your data, I would suggest removing all rows and adding a new one back in:
truncate table t;
insert into t(column_1)
values (1);
Be careful! The truncate table removes all rows from the table.

PostgreSQL: Inserting into one table then updating another using the same subquery, within the same single query

I have a fairly intricate query and I am finding it difficult to create the result of updating two different tables from the same subquery in the FROM. The difficulty I am facing is suggesting I have attempted the incorrect flow:
Below is an extremely simplified version of the script I have working for updating table1 from the subquery:
UPDATE
table1
SET
columnX= subquery.column2
FROM
(
SELECT column1, column2, column2
FROM table2
) AS subquery
WHERE subquery.column1 = table1.column1;
Now I need to bring a third table (table3) into the mix and map table2(subquery).column2 to a value on INSERT.
I cannot do this using a second query which would be ideal as the subquery generates UUID's that must persist across the table1.columnX and table3.column1.
Can I include the INSERT within the subquery whilst still returning the same subquery table?
INSERT...RETURNING uuid_column_name may be the magic you need in your subquery.
https://www.postgresql.org/docs/13/sql-insert.html

VERTICA insert multiple rows in one statement with named columns

I want to insert multiple rows efficiently into VERTICA. In PostgreSQL (and probably other SQL implementations) it is possible to INSERT multiple rows in one statement, which is a lot faster, than doing single inserts (especially when in Autocommit mode).
A minimal self-contained example to load two rows in a newly created table could look like this (a):
CREATE TABLE my_schema.my_table (
row_count int,
some_float float,
some_string varchar(8));
INSERT INTO my_schema.my_table (row_count, some_float, some_string)
VALUES (1,1.0,'foo'),(2,2.0,'bar');
But the beauty of this is, that the order in which the values are bunched can be changed to be something like (b):
INSERT INTO my_schema.my_table (some_float, some_string, row_count)
VALUES (1.0,'foo',1),(2.0,'bar',2);
Furthermore, this syntax allows for leaving out columns which are then filled by default values (such as auto incrementing integers etc.).
However, VERTICA does not seem to have the possibility to do a multi-row insert with the same fine-tuning. In fact, the only way to emulate a similar behaviour seems to be to UNION several selects together for something like (c):
INSERT INTO my_schema.my_table SELECT 1,1.0,'foo' UNION SELECT 2,2.0,'bar';
as in this answer: Vertica SQL insert multiple rows in one statement .
However, this seems to be working only, when the order of the inserted columns matches the order of their initial definition. My question is, it is possible to craft a single insert like (c) but with the possibility of changing column order as in (b)? Or am I tackling the problem completely wrong? If so, what alternative is there to a multi-row insert? Should I try COPY LOCAL?
Just list the columns in the insert:
INSERT INTO my_schema.my_table (row_count, some_float, some_string)
SELECT 1,1.0,'foo'
UNION ALL
SELECT 2,2.0,'bar';
Note the use of UNION ALL instead of UNION. UNION incurs overhead for removing duplicates, which is not needed.

Trying to use cursor on one database using select from another db

So I'm trying to wrap my head around cursors. I have task to transfer data from one database to another, but they have slightly diffrent schemas. Let's say I have TableOne (Id, Name, Gold) and TableTwo (Id, Name, Lvl). I want to take all records from TableTwo and insert it into TableOne, but it can be duplicated data on Name column. So if single record from TableTwo exist (on Name column comparison) in TableOne, I want to skip it, if don't - create record in TableOne with unique Id.
I was thinking about looping on each record in TableTwo, and for every record check if it's exist in TableOne. So, how do I make this check without making call to another database every time? I wanted first select all record from TableOne, save it into variable and in loop itself make check against this variable. Is this even possible in SQL? I'm not so familiar with SQL, some code sample would help a lot.
I'm using Microsoft SQL Server Management Studio if that matters. And of course, TableOne and TableTwo exists in diffrent databases.
Try this
Insert into table1(id,name,gold)
Select id,name,lvl from table2
Where table2.name not in(select t1.name from table1 t1)
If you want to add newId for every row you can try
Insert into table1(id,name,gold)
Select (select max(m.id) from table1 m) + row_number() over (order by t2.id) ,name,lvl from table2 t2
Where t2.name not in(select t1.name from table1 t1)
It is possible yes, but I would not recommend it. Looping (which is essentially what a cursor does) is usually not advisable in SQL when a set-based operation will do.
At a high level, you probably want to join the two tables together (the fact that they're in different databases shouldn't make a difference). You mention one table has duplicates. You can eliminate those in a number of ways such as using a group by or a row_number. Both approaches will require you understanding which rows you want to "pick" and which ones you want to "ignore". You could also do what another user posted in a comment where you do an existence check against the target table using a correlated subquery. That will essentially mean that if any rows exist in the target table that have duplicates you're trying to insert, none of those duplicates will be put in.
As far as cursors are concerned, to do something like this, you'd be doing essentially the same thing, except on each pass of the cursor you would be temporarily assigning and using variables instead of columns. This approach is sometimes called RBAR (for "Rob by Agonizing Row"). On every pass of the cursor or loop, it has to re-open the table, figure out what data it needs, then operate on it. Even if that's efficient and it's only pulling back one row, there's still lots of overhead to doing that query. So while, yes, you can force SQL to do what you've describe, the database engine already has an operation for this (joins) which does it far faster than any loop you could conceivably write