Update statement gives wrong result with subquery [duplicate] - sql

This question already has answers here:
sql server 2008 management studio not checking the syntax of my query
(2 answers)
Closed 4 years ago.
I have the following query which gives no error when I used a non-existent column reference in the subquery. The column which I referred in the subquery is actually a column in the table being updated.
create table tbl1 (f1 bigint, f2 char(10), f3 integer);
insert into tbl1 values (1, 'aa', 0);
insert into tbl1 values (2, 'bb', 0);
insert into tbl1 values (3, 'cc', 0);
insert into tbl1 values (4, 'dd', 0);
create table temp_tbl (ref_num bigint);
insert into temp_tbl values (1);
insert into temp_tbl values (3);
update tbl1 set f2='ok' where f1 in (select f1 from temp_tbl);
-- 4 records updated
can anyone tell me why it is not giving any error? and records are updated irrespective of the condition.
I tried this in both Oracle and SQLserver. results are same

The sub-query's column reference goes to the outer table!
update tbl1 set f2='ok' where f1 in (select f1 from temp_tbl);
Is read as
update tbl1 set f2='ok' where f1 in (select tbl1.f1 from temp_tbl);
Qualify your columns:
update tbl1 set f2='ok' where f1 in (select temp_tbl.ref_num from temp_tbl);

This is happening because the values in a SELECT don't just have to be columns from the table you're selecting from, the sub-query is returning the value for f1 from the outer query, instead of a value from temp_tbl.
Consider if you re-wrote the UPDATE query to:
SELECT *
FROM tbl1
WHERE f1 IN (select f1 from temp_tbl);
The results returned would actually be:
When you're trying to reason about something like this (and as a generally good way of working to get queries right!), it's useful to write your UPDATE query in the form:
UPDATE T
SET F2 = 'ok'
FROM TBL1 T
WHERE T.f1 IN
(
SELECT F1
FROM temp_tbl
)
By writing it this way you can readily comment out the UPDATE and SET components of the query, replace them with a SELECT and see what the set of data the query will operate on is.

Related

Update each row with a new entity

I have two tables:
CREATE TABLE public.test
(
id integer NOT NULL GENERATED ALWAYS AS IDENTITY
)
and
CREATE TABLE public.test2
(
id integer,
test_id integer
)
Table test2 has two rows (1, null) and (2, null). Table test has nothing. Now I want to fill test_id by creating new rows in test. I nead a new entity each time so that I will have (1, 1), (2, 2), etc. I try to prepare update query with an insert statement but I don't understand how to do it. This is what I try:
update t2 set t2.test_id = t.id
from test2 t2 full join (INSERT INTO test(id) VALUES (default) RETURNING id) t on t2.test_id = t.id
but I get the following:
ERROR: syntax error at or near "INTO"
LINE 2: from test2 t2 full join (INSERT INTO test(id) VALUES (defaul...
^
SQL state: 42601
Character: 65
Can I create the query I want somehow?
Having just one column in the target table makes things a little tricky. It might be simpler to generate and assign the new ids first, using next_val, and then insert the values in test (we need option overriding system value to insert into a generated always colum,)
with t2 as (
update test2
set test_id = nextval('test_id_seq')
where test_id is null
returning test_id
)
insert into test(id) overriding system value
select test_id from t2
Demo on DB Fiddlde

SQL - SQL statement has been terminated if one insert into row is incorrect

I'm trying to insert hundreds of rows into a table using a query like:
Insert INTO tableX (column1, colum2)
VALUES
((SELECT sysID FROM tableY where ID = var1), 1)
((SELECT sysID FROM tableY where ID = var2), 1)
et cetera
Now let's say var88 doesn't exist, it will return NULL as sysID, however I can't insert a NULL into column1 so I get an error and the whole insert into query will be terminated. Is there a way to cancel the whole termination and just skip the rows where sysID = NULL? I'm sure I can do this by first doing a proper select, filtering out the NULL rows and THEN do the insert into, however I'm wondering if there is an other way to do this.
You can use the following instead, using a INSERT INTO SELECT:
INSERT INTO tableX (column1, colum2)
SELECT sysID, 1
FROM tableY
WHERE ID IN (va1, var2) AND NOT sysID IS NULL
Where/how are you getting the var1 (etc) variables for your values?
You can convert this to:
Insert INTO tableX (column1, colum2)
VALUES
Select SELECT sysID, 1
Where ID IN (var1, var2, etc..)
WHERE sysID is not null
Or build this into a loop somehow (depending on where/how your var1 etc are coming from

Insert into Teradata

insert into tablex (a,b,c)
select distinct a,b,c
from tableA;
when I run select distinct statement alone it shows 6 rows.
When I run with insert it shows 0 rows inserted .
Is it a bug or AM I missing some thing.
#Teradata 13.10
masked original Query
INSERT INTO tablex
(SYSTEM_ID,START_DATE,END_DATE,CURRENT_FLAG )
SELECT DISTINCT
,s.SYSTEM_ID
,s.trans_DATE
,DATE '9999-12-31'
,'X'
FROM s JOIN cc
ON s.var_id=cc.var_id
WHERE s.sno = cc.sno
AND s.sno<>s.orino AND s.orino IS NOT NULL AND s.orino <> ''
AND cc.end_date=s.trans_date-1;
It's not a bug :-)
All six rows existed already in the target table and it's a SET table which automatically removes duplicate rows during an Insert/Select.

Update Null value

This question reflects my issue. How to do this in SQLite?
I've tried UPDATE with self-joins, isolating the self join in sub-query, triggers, and something similar to this. Here is an example:
UPDATE stage
SET title =
(
SELECT
prior.title
FROM
stage prior,
stage now
WHERE
prior.rownum+1 = now.rownum
)
WHERE
title is null
Every table in SQLite has got a pseudo-column called rowid (which can be accessible under several different names: rowid, oid, _rowid_, unless those names are assigned to other, real, columns). The rowid column is essentially a unique row identifier and you can use it as a sort criterion and/or in conditions.
The following query demonstrates how your problem can be solved with the help of rowid:
UPDATE stage
SET title = (
SELECT title
FROM stage AS prev
WHERE title IS NOT NULL AND prev.rowid < stage.rowid
ORDER BY prev.rowid DESC
LIMIT 1
)
WHERE title IS NULL
Here's a demo on SQL Fiddle.
You can read more about rowid in this SQLite manual.
I presented a solution for the problem you referred (I successfully tested on SQL2008, SQLite3 and Oracle11g). I copied that solution below:
CREATE TABLE test(mysequence INT, mynumber INT);
INSERT INTO test VALUES(1, 3);
INSERT INTO test VALUES(2, NULL);
INSERT INTO test VALUES(3, 5);
INSERT INTO test VALUES(4, NULL);
INSERT INTO test VALUES(5, NULL);
INSERT INTO test VALUES(6, 2);
SELECT t1.mysequence, t1.mynumber AS ORIGINAL
, (
SELECT t2.mynumber
FROM test t2
WHERE t2.mysequence = (
SELECT MAX(t3.mysequence)
FROM test t3
WHERE t3.mysequence <= t1.mysequence
AND mynumber IS NOT NULL
)
) AS CALCULATED
FROM test t1;
-- below here it was only tested in SQLite3, but I believe it should
-- work on other DBMS since it uses standard/non-proprietary SQL
UPDATE test
SET mynumber = (
SELECT t2.mynumber
FROM test t2
WHERE t2.mysequence = (
SELECT MAX(t3.mysequence)
FROM test t3
WHERE t3.mysequence <= test.mysequence
AND mynumber IS NOT NULL
)
);

How to do INSERT into a table records extracted from another table

I'm trying to write a query that extracts and transforms data from a table and then insert those data into another table. Yes, this is a data warehousing query and I'm doing it in MS Access. So basically I want some query like this:
INSERT INTO Table2(LongIntColumn2, CurrencyColumn2) VALUES
(SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 FROM Table1 GROUP BY LongIntColumn1);
I tried but get a syntax error message.
What would you do if you want to do this?
No "VALUES", no parenthesis:
INSERT INTO Table2(LongIntColumn2, CurrencyColumn2)
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 FROM Table1 GROUP BY LongIntColumn1;
You have two syntax options:
Option 1
CREATE TABLE Table1 (
id int identity(1, 1) not null,
LongIntColumn1 int,
CurrencyColumn money
)
CREATE TABLE Table2 (
id int identity(1, 1) not null,
LongIntColumn2 int,
CurrencyColumn2 money
)
INSERT INTO Table1 VALUES(12, 12.00)
INSERT INTO Table1 VALUES(11, 13.00)
INSERT INTO Table2
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 FROM Table1 GROUP BY LongIntColumn1
Option 2
CREATE TABLE Table1 (
id int identity(1, 1) not null,
LongIntColumn1 int,
CurrencyColumn money
)
INSERT INTO Table1 VALUES(12, 12.00)
INSERT INTO Table1 VALUES(11, 13.00)
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1
INTO Table2
FROM Table1
GROUP BY LongIntColumn1
Bear in mind that Option 2 will create a table with only the columns on the projection (those on the SELECT).
Remove both VALUES and the parenthesis.
INSERT INTO Table2 (LongIntColumn2, CurrencyColumn2)
SELECT LongIntColumn1, Avg(CurrencyColumn) FROM Table1 GROUP BY LongIntColumn1
I believe your problem in this instance is the "values" keyword. You use the "values" keyword when you are inserting only one row of data. For inserting the results of a select, you don't need it.
Also, you really don't need the parentheses around the select statement.
From msdn:
Multiple-record append query:
INSERT INTO target [(field1[, field2[, …]])] [IN externaldatabase]
SELECT [source.]field1[, field2[, …]
FROM tableexpression
Single-record append query:
INSERT INTO target [(field1[, field2[, …]])]
VALUES (value1[, value2[, …])
Remove VALUES from your SQL.
Remove "values" when you're appending a group of rows, and remove the extra parentheses. You can avoid the circular reference by using an alias for avg(CurrencyColumn) (as you did in your example) or by not using an alias at all.
If the column names are the same in both tables, your query would be like this:
INSERT INTO Table2 (LongIntColumn, Junk)
SELECT LongIntColumn, avg(CurrencyColumn) as CurrencyColumn1
FROM Table1
GROUP BY LongIntColumn;
And it would work without an alias:
INSERT INTO Table2 (LongIntColumn, Junk)
SELECT LongIntColumn, avg(CurrencyColumn)
FROM Table1
GROUP BY LongIntColumn;
Well I think the best way would be (will be?) to define 2 recordsets and use them as an intermediate between the 2 tables.
Open both recordsets
Extract the data from the first table (SELECT blablabla)
Update 2nd recordset with data available in the first recordset (either by adding new records or updating existing records
Close both recordsets
This method is particularly interesting if you plan to update tables from different databases (ie each recordset can have its own connection ...)
inserting data form one table to another table in different DATABASE
insert into DocTypeGroup
Select DocGrp_Id,DocGrp_SubId,DocGrp_GroupName,DocGrp_PM,DocGrp_DocType
from Opendatasource( 'SQLOLEDB','Data Source=10.132.20.19;UserID=sa;Password=gchaturthi').dbIPFMCI.dbo.DocTypeGroup
Do you want to insert extraction in an existing table?
If it does not matter then you can try the below query:
SELECT LongIntColumn1, Avg(CurrencyColumn) as CurrencyColumn1 INTO T1 FROM Table1
GROUP BY LongIntColumn1);
It will create a new table -> T1 with the extracted information