I am trying to delete data from two tables at the same time using inner join. However when I tried to run my query, an error
SQL command not properly ended
error came out.
A brief background of what I am trying to do and some info on the tables, table1 and table2. So both tables has a same field, for instance "ABC". I would like to delete data from both tables using inner join but under the where condition of a field (XYZ) under table where it equals to a value.
This is my sql statment:
DELETE table1, table2
FROM table1
INNER JOIN table1 ON table1.ABC = table2.ABC
WHERE table1.XYZ = 'TESTIT';
You can't delete more than one table.
You must use two different DELETE statements.
For this you can create a temporary table to store IDs to delete, for example:
CREATE TABLE app (ABC varchar(100))
INSERT INTO app (ABC)
SELECT abc
FROM table1
INNER JOIN table1 ON table1.ABC = table2.ABC
WHERE table1.XYZ = 'TESTIT';
DELETE
FROM table1
WHERE table1.ABC IN (SELECT ABC FROM app);
DELETE
FROM table2
WHERE table2.ABC IN (SELECT ABC FROM app);
DROP TABLE app;
In Oracle you cannot delete from 2 tables in a single statement like you are doing. The syntax is wrong. You can use as below:
DELETE table1
where table1.ABC = (select table2.ABC
from table2
WHERE table2.ABC = table1.ABC
and table1.XYZ = 'TESTIT');
A PL/SQL solution might be something like this:
declare
type abc_tt is table of table1.abc%type index by pls_integer;
l_abc_collection abc_tt;
begin
select distinct t1.abc bulk collect into l_abc_collection
from table1 t1
join table2 t2 on t2.abc = t1.abc
where t1.xyz = 'TESTIT';
dbms_output.put_line('Stored ' || l_abc_collection.count || ' values for processing');
forall i in 1..l_abc_collection.count
delete table1 t
where t.xyz = 'TESTIT'
and t.abc = l_abc_collection(i);
dbms_output.put_line('Deleted ' || sql%rowcount || ' rows from table1');
forall i in 1..l_abc_collection.count
delete table2 t
where t.xyz = 'TESTIT'
and t.abc = l_abc_collection(i);
dbms_output.put_line('Deleted ' || sql%rowcount || ' rows from table2');
end;
Output:
Stored 1000 values for processing
Deleted 1000 rows from table1
Deleted 1000 rows from table1
Test setup:
create table table1 (abc, xyz) as
select rownum, 'TESTIT' from dual connect by rownum <= 1000
union all
select rownum, 'OTHER' from dual connect by rownum <= 100;
create table table2 as select * from table1;
After deletion there are 100 rows in each table. I have assumed we only want to delete the ones where xyz = 'TESTIT' even when abc values are common to both tables.
select distinct table1.ABC into Temptable
FROM table1
INNER JOIN table1 ON table1.ABC = table2.ABC
WHERE table1.XYZ = 'TESTIT'
delete table1 where ABC in (select ABC from Temptable)
delete table2 where ABC in (select ABC from Temptable)
drop table Temptable
Related
If I run this query,
SELECT Qry_StockData_Names.CodeName
FROM Qry_StockData_Names LEFT JOIN Tbl_StockData_Codes ON Qry_StockData_Names.CodeName = Tbl_StockData_Codes.CodeName
WHERE Tbl_StockData_Codes.CodeName IS NULL;
it returns the CodeNames that are on Qry_StockData_Names but not on Tbl_StockData_Codes (Qry_StockData_Names is just a select distinct off existing data). How can I use the result from this and delete it from 3 tables. For example, say the return result is
CodeName
ABC
DEF
I would like to remove from Tbl_StockData_Daily, Tbl_StockData_Weekly and Tbl_StockData_Monthly all the data where the CodeName's are ABC, DEF.
IN Access you can do this
DELETE FROM Qry_StockData_Names AS t1
WHERE Exists (
SELECT t2.CodeName
FROM StockData_Codes AS t2
WHERE
t2.CodeName = t1.CodeName );
For each of the tables Tbl_StockData_Daily, Tbl_StockData_Weekly and Tbl_StockData_Monthly execute a DELETE statement, for example:
DELETE FROM Tbl_StockData_Daily
WHERE CodeName IN (
SELECT Qry_StockData_Names.CodeName
FROM Qry_StockData_Names LEFT JOIN Tbl_StockData_Codes
ON Qry_StockData_Names.CodeName = Tbl_StockData_Codes.CodeName
WHERE Tbl_StockData_Codes.CodeName IS NULL
);
Or with NOT EXISTS:
DELETE FROM Tbl_StockData_Daily
WHERE CodeName IN (
SELECT n.CodeName
FROM Qry_StockData_Names AS n
WHERE NOT EXISTS (
SELECT 1
FROM Tbl_StockData_Codes AS c
WHERE c.CodeName = n.CodeName
)
);
I am attempting to delete from multiple tables within a cursor in a DB2 system. However the terminator character ; is causing my cursor to exit prematurely. Currently I can not determine another way to set this query up to achieve the desired results.
I tried the below statement:
DECLARE C1 CURSOR FOR
DELETE FROM TABLE1 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM;
DELETE FROM TABLE2 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM;
DELETE FROM TABLE3 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM;
DELETE FROM TABLE4 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM;
DELETE FROM TABLE5 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM;
DELETE FROM TABLE6 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM;
DELETE FROM TABLE7 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM;
However this did not run as expected, meaning that it will not loop through a cursor, instead it just runs once.
This also fails to run:
--#SET TERMINATOR #
DECLARE C1 CURSOR FOR
SELECT * FROM TABLE1 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM#
SELECT * FROM TABLE2 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM#
SELECT * FROM TABLE3 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM#
SELECT * FROM TABLE4 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM#
SELECT * FROM TABLE5 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM#
SELECT * FROM TABLE6 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM#
SELECT * FROM TABLE7 WHERE ACCOUNT_NUMBER = ACCOUNT_NUMBER_PARAM#;
OPEN C1#
Here I tried to change the cursor terminator character so that it would get further down and actually open and run the cursor, however this threw a an error and did not run at all.
How can I rewrite this statement to run multiple select statements within a cursor?
After the OPEN C1 you need to loop through the results stored in the cursor.
with the
OPEN C1
FETCH NEXT FROM C1 INTO #Variable1,#Variable2,....( as many as fields in the table )
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM C1 INTO #Variable1,#Variable2,....( as many as fields in the table )
END
CLOSE CURSOR
DEALLOCATE CURSOS
why do you need a cursor to delete data?
It is far better to do this:
DELETE FROM table1 WHERE colname = (SELECT colname FROM table1 WHERE condition);
DELETE FROM table2 WHERE colname = (SELECT colname FROM table2 WHERE condition);
DELETE FROM table3 WHERE colname = (SELECT colname FROM table3 WHERE condition);
DELETE FROM table4 WHERE colname = (SELECT colname FROM table4 WHERE condition);
There should be no problem running this in a stored procedure.
We have 3 tables (table1, table2, table3), and I need to delete all the rows from table1 that have the same ID in table2 OR table3. To see a list of all of these rows I have this code:
(
select
table2.ID,
table2.name_first,
table2.name_last,
table2.Collected
from
table2
inner join
table1
on
table1.ID = table2.ID
where
table2.Collected = 'Y'
)
union
(
select
table3.ID,
table3.name_first,
table3.name_last,
table3.Collected
from
table3
inner join
table1
on
table1.ID = table3.ID
where
table3.Collected = 'Y'
)
I get back about 200 rows. How do I delete them from table1? I don't have a way to test if my query will work, so I'm nervous about modifying something I found online and potentially deleting data (we do have backups, but I'd rather not test out their integrity).
TIA!
EDIT
You are correct, we are on MSSQL 2008. Thanks so much for all the replies, I will try it out tomorrow!
Try this:
DELETE FROM Table1 WHERE
ID IN
(
SELECT ID FROM Table2 WHERE Collected = 'Y'
UNION ALL
SELECT ID FROM Table3 WHERE Collected = 'Y'
)
To test this query you can create dupicate tables using into clause i.e.(I assume it is SQL Server):
SELECT * INTO DUP_Table1 FROM Table1;
SELECT * INTO DUP_Table2 FROM Table2;
SELECT * INTO DUP_Table3 FROM Table3;
and then run this query:
DELETE FROM DUP_Table1 WHERE
ID IN
(
SELECT ID FROM DUP_Table2 WHERE Collected = 'Y'
UNION ALL
SELECT ID FROM DUP_Table3 WHERE Collected = 'Y'
)
EDIT: Added the Collected Criteria and used UNION ALL (#Thomas: Thanks..) I think performance of UNION ALL is better than UNION when there is no need for uniqueness in the result.
DELETE FROM table1
WHERE EXISTS (SELECT 1 FROM table2 WHERE table2.id = table1.id AND table2.collected = 'Y')
OR EXISTS (SELECT 1 FROM table3 WHERE table3.id = table1.id AND table3.collected = 'Y')
If you're feeling nervous about a big delete like this, put it into a transaction: that way you can at least check the row count before running commit (or rollback, of course :p)
Make sure foreign keys are setup properly and turn on cascade deletes. But if that's not an option, the correct SQL query is as follows:
begin tran
delete from table1
where exists(select * from table2 where table1.id = id and collected='Y')
or exists(select * from table3 where table1.id = id and collected='Y')
-- commit tran
-- rollback tran
if the SQL runs as expected, execute the "commit tran", otherwise execute the "rollback tran".
I need to write an SQL script that selects one record in table1, then does a lookup in the remaining tables in the database. If it doesn't find the record, I need delete the record from table1. Anyone provide some sample script?
One example
delete table1
where not exists (select 1
from Table2
where table1.SomeColumn = Table2.SomeColumn)
AND table1.SomeColumn = 5 --just an example,
Leave the AND out if you want to delete all the rows from table 1 that do not exist in table 2
you can also use LEFT JOIN or NOT IN
I have done things like this:
DELETE table1
FROM table1
WHERE table1.ID NOT IN (
SELECT RefID FROM Table2
UNION
SELECT RefID FROM Table3
...
)
Assuming RefID are FK's to table1.ID. Is this what you need?
DELETE FROM Table1 WHERE id=10 AND NOT EXISTS (SELECT * FROM Table2 WHERE id=10);
Very generally, (since you gave little details)
Delete Table1 t1
Where [Criteria to find table1 Record]
And Not Exists(Select * From Table2
Where pk = t1.Pk)
And Not Exists(Select * From Table3
Where pk = t1.Pk)
And Not Exists(Select * From Table4
Where pk = t1.Pk)
... etc. for all other tables
Here is my situation:
Table one contains a set of data that uses an id for an unique identifier. This table has a one to many relationship with about 6 other tables such that.
Given Table 1 with Id of 001:
Table 2 might have 3 rows with foreign key: 001
Table 3 might have 12 rows with foreign key: 001
Table 4 might have 0 rows with foreign key: 001
Table 5 might have 28 rows with foreign key: 001
I need to write a report that lists all of the rows from Table 1 for a specified time frame followed by all of the data contained in the handful of tables that reference it.
My current approach in pseudo code would look like this:
select * from table 1
foreach(result) {
print result;
select * from table 2 where id = result.id;
foreach(result2) {
print result2;
}
select * from table 3 where id = result.id
foreach(result3) {
print result3;
}
//continued for each table
}
This means that the single report can run in the neighbor hood of 1000 queries. I know this is excessive however my sql-fu is a little weak and I could use some help.
LEFT OUTER JOIN Tables2-N on Table1
SELECT Table1.*, Table2.*, Table3.*, Table4.*, Table5.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.ID
LEFT OUTER JOIN Table3 ON Table1.ID = Table3.ID
LEFT OUTER JOIN Table4 ON Table1.ID = Table4.ID
LEFT OUTER JOIN Table5 ON Table1.ID = Table5.ID
WHERE (CRITERIA)
Join doesn't do it for me. I hate having to de-tangle the data on the client side. All those nulls from left-joining.
Here's a set-based solution that doesn't use Joins.
INSERT INTO #LocalCollection (theKey)
SELECT id
FROM Table1
WHERE ...
SELECT * FROM Table1 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table2 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table3 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table4 WHERE id in (SELECT theKey FROM #LocalCollection)
SELECT * FROM Table5 WHERE id in (SELECT theKey FROM #LocalCollection)
Ah! Procedural! My SQL would look like this, if you needed to order the results from the other tables after the results from the first table.
Insert Into #rows Select id from Table1 where date between '12/30' and '12/31'
Select * from Table1 t join #rows r on t.id = r.id
Select * from Table2 t join #rows r on t.id = r.id
--etc
If you wanted to group the results by the initial ID, use a Left Outer Join, as mentioned previously.
You may be best off to use a reporting tool like Crystal or Jasper, or even XSL-FO if you are feeling bold. They have things built in to handle specifically this. This is not something the would work well in raw SQL.
If the format of all of the rows (the headers as well as all of the details) is the same, it would also be pretty easy to do it as a stored procedure.
What I would do: Do it as a join, so you will have the header data on every row, then use a reporting tool to do the grouping.
SELECT * FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.resultid -- this could be a left join if the table is not guaranteed to have entries for t1.id
INNER JOIN table2 t3 ON t1.id = t3.resultid -- etc
OR if the data is all in the same format you could do.
SELECT cola,colb FROM table1 WHERE id = #id
UNION ALL
SELECT cola,colb FROM table2 WHERE resultid = #id
UNION ALL
SELECT cola,colb FROM table3 WHERE resultid = #id
It really depends on the format you require the data in for output to the report.
If you can give a sample of how you would like the output I could probably help more.
Join all of the tables together.
select * from table_1 left join table_2 using(id) left join table_3 using(id);
Then, you'll want to roll up the columns in code to format your report as you see fit.
What I would do is open up cursors on the following queries:
SELECT * from table1 order by id
SELECT * from table1 r, table2 t where t.table1_id = r.id order by r.id
SELECT * from table1 r, table3 t where t.table1_id = r.id order by r.id
And then I would walk those cursors in parallel, printing your results. You can do this because all appear in the same order. (Note that I would suggest that while the primary ID for table1 might be named id, it won't have that name in the other tables.)
Do all the tables have the same format? If not, then if you have to have a report that can display the n different types of rows. If you are only interested in the same columns then it is easier.
Most databases have some form of dynamic SQL. In that case you can do the following:
create temporary table from
select * from table1 where rows within time frame
x integer
sql varchar(something)
x = 1
while x <= numresults {
sql = 'SELECT * from table' + CAST(X as varchar) + ' where id in (select id from temporary table'
execute sql
x = x + 1
}
But I mean basically here you are running one query on your main table to get the rows that you need, then running one query for each sub table to get rows that match your main table.
If the report requires the same 2 or 3 columns for each table you could change the select * from tablex to be an insert into and get a single result set at the end...