UPSERT for "INSERT INTO tab SELECT * FROM another_tab" - sql

How would I do "UPSERT" (INSERT OR UPDATE) into SQLite table when inserting multiple rows from another table.
I've tried:
INSERT INTO tab_name
SELECT * FROM tmp
ON CONFLICT(id)
DO UPDATE SET
val = excluded.val;
But it gives me:
syntax error near "DO"
What would be the correct and the most efficient way to achieve that?

You might have hit a documented trap called parsing ambiguity :
When the INSERT statement to which the UPSERT is attached takes its values from a SELECT statement, there is a potential parsing ambiguity. The parser might not be able to tell if the "ON" keyword is introducing the UPSERT or if it is the ON clause of a join. To work around this, the SELECT statement should always include a WHERE clause, even if that WHERE clause is just "WHERE true".)
So, does this work better?
INSERT INTO tab_name
SELECT * FROM tmp WHERE true
ON CONFLICT(id) DO UPDATE SET val = excluded.val;

Related

sql ORA-00900: Invalid SQL statement

please help
IF EXISTS(SELECT * FROM MERC_ADM_VERSION )then UPDATE MERC_ADM_VERSION SET
VER_VALEUR = 20150409 WHERE VER_CLE = 'MEAD' ELSE INSERT INTO MERC_ADM_VERSION
('VER_VALEUR', 'VER_CLE') VALUES (20150409, 'MEAD');
ORA-00900: Invalid SQL statement
Remove the single quotes from the columns in the insert statement.
Instead of
('VER_VALEUR', 'VER_CLE')
It should be
(VER_VALEUR, VER_CLE)
Your question is quite unclear as to what you are trying to do. However, my best interpretation is you are looking for an oracle merge statement. Below is an example based on assumptions I made on the little information you provided. You are most likely looking for a MERGE statement. This allows you to perform a single operation that can either update or insert based on your criteria.
Also, you appear to be using a date, but in number format. I did nothing to address this due to lack of any table definition. You may still have problems with it.
MERGE
INTO merc_adm_version TARGET -- The table you want to update/insert into
USING (SELECT 20150409 as ver_valeur, 'MEAD' as ver_cle FROM dual) SOURCE -- The source of the data
ON (TARGET.ver_cle = SOURCE.ver_cle) -- How to try and match records between source and target
WHEN MATCHED THEN UPDATE SET ver_valeur = 20150409 -- When there is a match, how to update
WHEN NOT MATCHED THEN INSERT (ver_cle, ver_valeur) -- When there is not a match, how to insert
VALUES ('MEAD', 20150409);

Return deleted rows in sqlite

It's not efficient to do two queries like SELECT * FROM TABLE WHERE clause and then DELETE * FROM TABLE WHERE clause.
So I want to make DELETE query and return deleted rows (one query).
I tried to do:
DELETE OUTPUT DELETED.*
FROM table
WHERE clause
But I have an error:
SQLite exception: near "OUTPUT": syntax error
How to make it correctly or maybe there is another alternative way to return deleted rows?
The DELETE statement has no OUTPUT clause.
After doing the SELECT, all the important data is in the cache, so the DELETE will run quickly.
And because SELECT plus DELETE is the only way, it is the most efficient way.
Since version 3.35, SQLite has the RETURNING clause.
You can return the records deleted with the returning clause
delete from myTable returning *
You can use the changes() call right after your DELETE query: https://www.sqlite.org/c3ref/changes.html
Implementation will vary depending on the language you're using. For example in PHP you could write:
$sqlite = new SQLite3('database.sqlite');
$statement = $sqlite->prepare('DELETE FROM mytable WHERE myclause');
$statement->execute();
echo $sqlite->changes();

Update multiple values in an oracle table using values from an APEX collection

I am using APEX collections to store some values and pass them between pages in Oracle Application Express 4.2.3.
I would like to then perform an update statement on a table called "project" with the values from the collection.
My code so far is as follows:
update project
SET name=c.c002,
description=c.c007,
start_date=c.c004,
timeframe=c.c005,
status=c.c009
FROM
apex_collections c
WHERE
c.collection_name = 'PROJECT_DETAILS_COLLECTION'
and id = :p14_id;
where :p14_id is the value of a page item.
However, I am getting the following error:
ORA-00933: SQL command not properly ended
Anyone have any idea on how to approach this?
Thanks!
The UPDATE syntax you are using is not valid in Oracle; it does not allow you to use FROM in the way you are attempting.
The simplest way to do this in Oracle would with a subquery:
update project
set (name, description, start_date, timeframe, status) =
(select c.c002, c.c007, c.c004, c.c005, c.c009
FROM
apex_collections c
WHERE
c.collection_name = 'PROJECT_DETAILS_COLLECTION'
)
WHERE
id = :p14_id
;
Note that if the subquery returns no rows, the columns in the target table will be updated to NULL; this could be avoided by adding a similar EXISTS condition in the predicate for the update. It could also be avoided by using a MERGE statement instead of an UPDATE.
If the subquery returns multiple rows, the statement will throw an error. It looks like tthat should not be the case here.

insert a row into table in pl/pgsql

I am trying to update two tables by inserting some rows into the other. But when I try to do something like this :
BEGIN
FOR id IN (SELECT id FROM table1) LOOP
PERFORM (INSERT INTO anothertable VALUES(id));
END LOOP;
END;
It gives an error I don't know why. syntax error at or near "INTO".
Is it even possible to do such thing without cursors and such updating one by one ?
This is example of bad using PERFORM and bad plpgsql programming style. You must not use a PERFORM there. You should not use a parenthesis there (PL/pgSQL is based on ADA language - not C!). Some correct patterns are:
FOR _id IN
SELECT s.id
FROM sometab s
LOOP
INSERT INTO othertab(id) VALUES(_id);
END LOOP;
or faster (and shorter) pattern
INSERT INTO othertab(id)
SELECT id
FROM other tab
I used a qualified name and prefixes to reduce a risk of conflict between SQL identifiers and PL/pgSQL variables.
Note: PERFORM is implemented as SELECT statement without result processing. So your statement was SELECT (INSERT INTO tab ...) what is unsupported feature now.
why don't you insert it like this:
insert into anothertable
select id from table

Why do SQL INSERT and UPDATE Statements have Different Syntaxes?

While contemplating this question about a SQL INSERT statement, it occurred to me that the distinction in syntax between the two statements is largely artificial. That is, why can't we do:
INSERT INTO MyTable SET Field1=Value1, Field2=Value2, ...
or
UPDATE MyTable ( Field1, Field2 ...) VALUES ( Value1, Value2, ... )
WHERE some-key = some-value
Perhaps I'm missing something critical. But for those of us who have had to concatenate our SQL statements in the past, having comparable syntax for an INSERT and an UPDATE statement would have saved a significant amount of coding.
They're serving different grammatical functions. In an update you are specifying a filter that chooses a set of rows to which you will apply an update. And of course that syntax is shared with a SELECT query for the same purpose.
In an INSERT you are not choosing any rows, you are generating a new row which requires specifying a set of values.
In an UPDATE, the LHS=RHS stuff is specifying an expression which yields true or false (or maybe null :) and in an INSERT, the VALUES clause is about assignment of value. So while they are superficially similar, they are semantically quite different, imho. Although I have written a SQL parser, so that may influence my views. :)
SQL Server 2008 has introduced UPSERT functionality via the MERGE command. This is the logical equivalent of
IF FOUND THEN
UPDATE
ELSE
INSERT
I believe this is so that you may make an insert statement without being explicit about the values. If you are putting a value in every single column in the table you can write:
insert into my_table values ("value1", 2);
instead of:
insert into my_table (column1, column2) values ("value1", 2);
When importing and exporting entire (large) databases, this is invaluable for cutting down file size and processing time. Nowadays, with binary snapshots and the like, it may be "less invaluable" :-)