How to delete two records from two tables? - sql

Hello I need to be able to search for a record that is a year old and then delete it. I have this script which allows me to delete the record from one table, based on a date given by another table,however I need to add code to this so that I am able to delete a record from a different table relating to CardID. The table that I need to delete from is table11 and Primary key is CardID.
I think I need a left join, but I am not to sure on how to go about it.
DECLARE #deleted TABLE (Card INT)
INSERT INTO #deleted
SELECT Card FROM table9
WHERE recordstatus = 4
DELETE table9
FROM #deleted d, table51
WHERE table51.ActionString LIKE '%' + CAST(d.card AS VARCHAR(20))+ '%'
AND table51.AuditDate <= (SELECT CONVERT(VARCHAR(8),today,112) FROM(SELECT DATEADD(YEAR,-1,GETDATE()) AS today)aa)
AND table09.Card = d.card
Thanks in advance, Hope you can help.

same as this question
edit: as #HLGEM mentioned, the WHERE clause goes where you expect it to go, after the join.

Related

Automatically remove a row without foreign references

I am using sqlite3.
I have one "currencies" table, and two tables that reference the currencies table using a foreign key, as follows:
CREATE TABLE currencies (
currency TEXT NOT NULL PRIMARY KEY
);
CREATE TABLE table1 (
currency TEXT NOT NULL PRIMARY KEY,
FOREIGN KEY(currency)
REFERENCES currencies(currency)
);
CREATE TABLE table2 (
currency TEXT NOT NULL PRIMARY KEY,
FOREIGN KEY(currency)
REFERENCES currencies(currency)
);
I would like to make sure that rows in the "currencies" table that are not referenced by any row from "table1" and "table2" will be removed automatically. This should behave like some kind of ref-counted object. When the reference count reaches zero, the relevant row from the "currencies" table should be erased.
What is the "SQL way" to solve this problem?
I am willing to redesign my tables if it could lead to an elegant solution.
I prefer to avoid solutions that require extra work from the application side, or solutions that require periodic cleanup.
Create an AFTER DELETE TRIGGER in each of table1 and table2:
CREATE TRIGGER remove_currencies_1 AFTER DELETE ON table1
BEGIN
DELETE FROM currencies
WHERE currency = OLD.currency
AND NOT EXISTS (SELECT 1 FROM table2 WHERE currency = OLD.currency);
END;
CREATE TRIGGER remove_currencies_2 AFTER DELETE ON table2
BEGIN
DELETE FROM currencies
WHERE currency = OLD.currency
AND NOT EXISTS (SELECT 1 FROM table1 WHERE currency = OLD.currency);
END;
Every time that you delete a row in either table1 or table2, the trigger involved will check the other table if it contains the deleted currency and if it does not contain it, it will be deleted from currencies.
See the demo.
There is no automatic way of doing this. The reverse can be handling using cascading delete foreign key references. The reverse is that when a currency is deleted all related rows are.
You could schedule a job daily running something like:
delete from currencies c
where not exists (select 1 from table1 t1 where t1.currency = c.currency) and
not exists (select 1 from table2 t2 where t2.currency = c.currency);
If you need an automatic way for doing that, then most dbms provide a trigger mechanism. You can create a trigger on update and delete operations that run the folowing query:
you can use a left join for that:
https://www.w3schools.com/sql/sql_join_left.asp
It return a row for all rows from the left table, even if there is no corresponding row in the right table, replacing the rows form the right with null. You can then check a not null right table field for null with is null. This will filter for the rows the have no counterpart in the right table.
For example:
SELECT currencies.currency FROM currencies LEFT JOIN table1 WHERE table1.currency IS NULL
will show the relevant rows for table1.
You can do the same with table two.
This will give you two queries, that shows which rows have no couterpart.
You can then use intersect on the result, so that you have the rows that have not couterpart in either:
SELECT * FROM query1 INTERSECT SELECT * FROM query2
Now you have the list of currencies to be deleted.
You can finish this by using a subqueried delete:
DELETE FROM currencies WHERE currency IN (SELECT ...)

How can I delete the yonguer musician in a SQL statement?

I have the following table musician_groups:
This table is sorted but I need to delete the duplicated titles.
In the table, I have 4 Master of puppets I need to get only the first one and delete the others.
I need something like this:
Cliff Burton is on the top because is older than Kirk Hammet.
Someone can illuminate me?
Best regards,
Please use below query:
delete from musician_groups
where id not in (SELECT * from (SELECT MIN(n.id) FROM musician_groups n GROUP BY n.title) x )
"first" is not well defined in SQL. But you can keep one of the names, such as the first alphabetically:
delete from musician_groups mg
where mg.name > (select max(mg2.name)
from musician_groups mg2
where mg2.title = mg.title
);
If you do have an id column or another way to choose the row you want to keep, then you can use that.
If you have a large table, deleting large numbers of rows is expensive. Often, the fastest method is to re-insert into the table:
create table temp_musician_groups as
select distinct on (title) mg.*
from musician_groups mg
order by title, name;
truncate table musician_groups; -- back up the table first!
insert into musician_groups
select *
from temp_musician_groups;

Determining whether a foreign key value exists in any of multiple tables that have thousands of records

When the user clicks a delete button in my UI to delete a product I need to do a fast check to see if it is a foreign key in any of the 4 tables (Table1, Table2, Table3, Table4). If it isn't then I can proceed with the delete. If it is in a single one of them I can't delete it.
Some of these tables have thousands of records and I already learned the hard way that using joins is not the best way because the query takes minutes to complete.
I figured union might be the best way but I am wondering if there is a way I can further enhance it. Or even possibly send back which tables it is involved in so I can give the user a descriptive message on why they can't delete the Product.
Here is what I have so far and it is really fast, but returns thousands of 1's when the product exists all over the place. I suppose I can just do a single or default and if not null then don't let them delete.
select 1
from (
select ProductId from Table1
union all
select ProductId from Table2
union all
select ProductId from Table3
union all
select ProductId from Table4
) tbl
where ProductId = 1000
Here is a method with exists and case:
select (case when exists (select 1 from table1 where productId = 1000) then 1
when exists (select 1 from table2 where productId = 1000) then 1
when exists (select 1 from table3 where productId = 1000) then 1
when exists (select 1 from table4 where productId = 1000) then 1
else 0
end)
One way is to not define any "on delete" clauses when creating the foreign keys. Then just go ahead and try to delete the record. If there is no foreign key in any table referencing that record, the delete will succeed and you go about business as normal. If there is a foreign key in any table referencing that record, the delete will fail. Catch the error and try to give the user a meaningful message: "This customer cannot be deleted as they have at least one order still pending."
This way the system itself will perform the check for you, which will assuredly be more efficient than any check you can perform at the SQL level.

SQL delete records in order

Given the table structure:
Comment
-------------
ID (PK)
ParentCommentID (FK)
I want to run DELETE FROM Comments to remove all records.
However, the relationship with the parent comment record creates a FK conflict if the parent comment is deleted before the child comments.
To solve this, deleting in reverse ID order would work. How do I delete all records in a table in reverse ID order?
The following will delete all rows that are not themselves parents. If the table is big and there's no index on ParentCommentID, it might take a while to run...
DELETE Comment
from Comment co
where not exists (-- Correlated subquery
select 1
from Comment
where ParentCommentID = co.ID)
If the table is truly large, a big delete can do bad things to your system, such as locking the table and bloating the transaction log file. The following will limit just how many rows will be deleted:
DELETE top (1000) Comment -- (1000 is not very many)
from Comment co
where not exists (-- Correlated subquery
select 1
from Comment
where ParentCommentID = co.ID)
As deleting some but not all might not be so useful, here's a looping structure that will keep going until everything's gone:
DECLARE #Done int = 1
--BEGIN TRANSACTION
WHILE #Done > 0
BEGIN
-- Loop until nothing left to delete
DELETE top (1000) Comment
from Comment co
where not exists (-- Correlated subquery
select 1
from Comment
where ParentCommentID = co.ID)
SET #Done = ##Rowcount
END
--ROLLBACK
This last, of course, is dangerous (note the begin/end transaction used for testing!) You'll want WHERE clauses to limit what gets deleted, and something or to ensure you don't somehow hit an infinite loop--all details that depend on your data and circumstances.
With separate Parent and Child tables, ON DELETE CASCADE would ensure that deleting the parent also deletes the children. Does it work when both sets of data are within the same table? Maybe, and I'd love to find out!
How do I use cascade delete with SQL server.
this works (you can try replacing the subquery with top...)
create table #a1 (i1 int identity, b1 char(5))
insert into #a1 values('abc')
go 5
while ( (select count(*) from #a1 ) > 0)
begin
delete from #a1 where i1=(select top 1 i1 from #a1 order by i1 desc)
end

How do you do a update if you don't know the id, and just you know a information with another table relationed

I am trying to do this query:
UPDATE asignaturasemestre
SET asignatura11 = 'cambiado'
WHERE asignaturasemestre.iddatosgenerales = datosgenerales.iddatosgenerales
AND datosgenerales.curp = 'CURP'
I know this is bad, but this is the idea:
As you can see, I don't know the iddatosgenerales, but I do know it has a foreign key (iddatosgenerales). The users will write the curp only, so with that curp is not in the another table, so I need to update the another table but I don't know the id of this row.
As I have told you, I just know the CURP column, but this is in the another table (this is unique). But it is not the primary key - it doesn't mind, the id is iddatosgenerales which is a foreign key in the another table where I want to update.
This is for MySQL:
UPDATE asignaturasemestre AS a
, datosgenerales AS d
SET a.asignatura11='cambiado'
WHERE a.iddatosgenerales=d.iddatosgenerales
AND d.curp='CURP'
And this for SQL-Server:
UPDATE a
SET a.asignatura11='cambiado'
FROM asignaturasemestre AS a
JOIN datosgenerales AS d
ON a.iddatosgenerales=d.iddatosgenerales
WHERE d.curp='CURP'
update asignaturasemestre,datosgenerales
set asignatura11='cambiado'
where asignaturasemestre.iddatosgenerales=datosgenerales.iddatosgenerales
and datosgenerales.curp='CURP'
Now i have found the answer it is
update asignaturasemestre set asignatura11='cambiado'
where iddatosgenerales=(select datosgenerales.iddatosgenerales from datosgenerales inner join asignaturasemestre on
datosgenerales.iddatosgenerales=asignaturasemestre.iddatosgenerales where curp='123ABC');
I did the query normal, but when i put the iddatosgenerales i do a query getting the iddatosgenerales with curp user gave me