SQL DELETE FROM several tables - sql

I have the following tables:
dataset, links, files
dataset has a field called tiComplete, if it is 0 then the record is incomplete, links and files both have a field "biDataset" that references the record in the dataset table.
I'm trying to create a query that deletes all entries from dataset, links and files where tiComplete = 0, this is what I have:
DELETE
`datasets`.*,
`links`.*,
`files`.*
FROM
`datasets` `d`
INNER JOIN
`links` `l`
ON
`l`.biDataset=`d`.biPK
INNER JOIN
`files` `f`
ON
`f`.biDataset=`d`.biPK
WHERE
`d`.tiComplete=0;
However when I try to save the procedure that contains this I get:
SQL Error(1109): Unknown table `datasets` in MULTI DELETE
I'm using MariaDB version 10 with HeidiSQL version 11.0.0.5919

Your multiple table delete syntax is off. Use this version:
DELETE d, l, f
FROM datasets d
INNER JOIN links l ON l.biDataset = d.biPK
INNER JOIN files f ON f.biDataset = d.biPK
WHERE d.tiComplete = 0;
If you alias the tables, as you have done, then the aliases whose tables are intended for deletion should appear in the DELETE clause as a CSV list.
Note that I removed the ugly backticks everywhere, which weren't necessary and only obfuscate the code. Also, an alternative approach here would be to look into cascading deletion. Using that approach, deletion of a record in the parent table would automatically delete all records in linked children tables.

Related

github_repos: Join "commits" and "content" table

I want to retrieve the file content of a file at a given commit in Googles BigQuery Github Dataset ("github_repos").
Hence I would expect something like SELECT content FROM sample_contents WHERE commit_id = abc (just as one example. In the future it should be a join). But sadly I am not able to find a link i.e. an attribute which is shared between the commits-table and the contents-table.
How can I join the tables commits and contents?
You need to use the table file to join these two tables commits and contents.
You can see this example:
with example as (
SELECT a.id as idFiles,b.id as idContents,a.repo_name as idContents_1,c.repo_name as idCommit_1
FROM `files` a
join `contents` b on a.id=b.id
join `commits` c on a.repo_name=ARRAY_TO_STRING(c.repo_name, "")
where a.repo_name='conda-forge/feedstocks' and a.id='c798dafa5d536d96203f762db8fd11cbde8f3139'
)
select *
from example limit 10
As you can see in this image, the table files uses the field id to join the table contents because it uses the same id field. The table files uses the field repo_name to join the table commit. You must use the table files to join the tables commit and contents. You can’t join these two tables directly (commit and contents).

How to LEFT JOIN 4 tables in SQL?

I have 4 tables - Controls, Risks, Processes & Regulations. They each have ID common instances of ID numbers. For example (ID1 exists across the 4 tables). The problem is that under each table, the number of instances of each ID varies (for ex, ID1 exists 5 times in Controls, 3 times in Risks, 0 in Processes & once in Regulations).
I need to LEFT JOIN all these tables so they are all joined by ID number
The code below works until Line 3, but when I add Line 4, it gives me a "Resultant table not allowed to have more than one AutoNumber field" error
SELECT *
FROM Controls
LEFT JOIN Processes ON Processes.TO_PRC_ID = Controls.TO_PRC_ID
LEFT JOIN Risks ON Risks.TO_PRC_ID = Controls.TO_PRC_ID
LEFT JOIN Regulations ON Regulations.TO_PRC_ID = Controls.TO_PRC_ID
MS Access requires extra parentheses for multiple joins:
SELECT *
FROM (Controls LEFT JOIN
Processes_Risks
ON Processes_Risks.TO_PRC_ID = Controls.TO_PRC_ID
) LEFT JOIN
Issues
ON Issues.TO_PRC_ID = Controls.TO_PRC_ID
And the process continues:
SELECT *
FROM ((Controls LEFT JOIN
Processes_Risks
ON Processes_Risks.TO_PRC_ID = Controls.TO_PRC_ID
) LEFT JOIN
Issues
ON Issues.TO_PRC_ID = Controls.TO_PRC_ID
) LEFT JOIN
Regulations
ON . . .
You have two or more table with the same column name so try use full qualified column name in select
SELECT c.TO_PRC_ID, p.TO_PRC_ID, r1.TO_PRC_ID, r2.TO_PRC_ID
FROM Controls c
LEFT JOIN Processes ON p p.TO_PRC_ID = c.TO_PRC_ID
LEFT JOIN Risks r1 ON r1.TO_PRC_ID = c.TO_PRC_ID
LEFT JOIN Regulations r2 ON r2.TO_PRC_ID = c.TO_PRC_ID
There are two different problems here. One problem is getting the right syntax for joining four tables. The other problem is the error message "Resultant table not allowed to have more than one AutoNumber field".
I don't have a copy of the tables being joined, but I suspect that more than one of them has an AutoNumber field in it. This is a field that automatically generates a record number when a new record is added to a table. Because the left join includes all of the fields in all of the tables, it will eventually include two different AutoNumber fields. MS Access cannot cope with that situation, so it declares there to be an error.
The proper though difficult way to deal with removing an AutoNumber field from a join is to list all of the other fields instead. So, instead of
FROM CONTROLS
one would need to code
FROM (SELECT A, B, C, D, WHATEVER FROM CONTROLS)
to eliminate the problem field.
If the tables have many fields, this becomes tedious to code. One alternative is to copy a table into a temporary table, drop the AutoNumber field from the copy, and use the copy instead of the original in the join. Whether this is a good or bad idea depends on the circumstances, such as how large the tables are, how often this would need to be done, and whether there is a good way to clean up the temporary tables later.

Delete s from table

I have a query as following (not the actual one):
DELETE s
FROM
table_expiration s INNER JOIN table_existance d
ON s.ssn = d.ssn AND
s.latest_date = d.latest_date
I don't have any data in those tables so I cannot actually test the query. Can someone explain to me what's the purpose of Delete s? (I always thought the Delete statement should just be Delete from table)
delete s tells the query to delete the rows from table_expiration which has the alias s. Replacing s with d would delete rows from table_existance.
SQLFiddle
It may be worth pointing out here that you cannot delete from both tables involved in the join directly by doing delete s,d in SQL Server (MySQL lets you do that I think).

Concatenating fields

This is an MS Access (2010) script.
I am trying to concatenate 2 fields of a single table for 2 tables. Then I want to delete the associated record in one of the table if the concatenated field is equal in both tables (means this is a duplicate).
I know how to do that in VBA by looping through the records but I want to do that in SQL since the tables may quickly hold more than 50000 records which means the loop would go 2,500,000,000 times.
I though I could create a 2 SELECT statement in order to create the concatenated fields for both tables. The SELECT Statements will also display the ID of the underlying tables. Then I would delete the record in the appropriate table using the ID.
These are my Select statements:
SELECT [Tick] & [Div_ex_date] AS Expr2, tblBbgDivData.ID
FROM tblBbgDivData
GROUP BY [Tick] & [Div_ex_date], tblBbgDivData.ID;
And
SELECT [Security_Name] & [Div_ex_date] AS Expr1, tblArchiveBbgDivData.ID
FROM tblArchiveBbgDivData
GROUP BY [Security_Name] & [Div_ex_date], tblArchiveBbgDivData.ID;
This is my DELETE Statement:
DELETE tblArchiveBbgDivData.*
FROM (tblArchiveBbgDivData
INNER JOIN qselUniqueID_Archive ON tblArchiveBbgDivData.ID = qselUniqueID_Archive.ID)
INNER JOIN qselUniqueID_BbgDiv ON qselUniqueID_Archive.Expr1 = qselUniqueID_BbgDiv.Expr2
WHERE (((tblArchiveBbgDivData.ID)=[qselUniqueID_Archive].[ID])
AND ((qselUniqueID_Archive.Expr1)=[qselUniqueID_BbgDiv].[Expr2]));
When I hit Datasheet view, the relevant records are displayed but when I hit Run I get "Could not delete from specified tables". Any idea how I can change that?
Access does not work well with JOINs in a DELETE statement. You may be better off with an IN:
DELETE tblArchiveBbgDivData.*
FROM (tblArchiveBbgDivData
WHERE tblArchiveBbgDivData.ID IN
(SELECT qselUniqueID_Archive.ID
FROM qselUniqueID_Archive )
INNER JOIN qselUniqueID_BbgDiv
ON qselUniqueID_Archive.Expr1 = qselUniqueID_BbgDiv.Expr2
);
Note that your WHERE is redundant because you use the same expression in your JOIN syntax.

Delete all records that have no foreign key constraints

I have a SQL 2005 table with millions of rows in it that is being hit by users all day and night. This table is referenced by 20 or so other tables that have foreign key constraints. What I am needing to do on a regular basis is delete all records from this table where the "Active" field is set to false AND there are no other records in any of the child tables that reference the parent record. What is the most efficient way of doing this short of trying to delete each one at a time and letting it cause SQL errors on the ones that violate constraints? Also it is not an option to disable the constraints and I cannot cause locks on the parent table for any significant amount of time.
If it's not likely that inactive rows which are not linked will become linked, you can run (or even dynamically build, based on the foreign key metadata):
SELECT k.*
FROM k WITH(NOLOCK)
WHERE k.Active = 0
AND NOT EXISTS (SELECT * FROM f_1 WITH(NOLOCK) WHERE f_1.fk = k.pk)
AND NOT EXISTS (SELECT * FROM f_2 WITH(NOLOCK) WHERE f_2.fk = k.pk)
...
AND NOT EXISTS (SELECT * FROM f_n WITH(NOLOCK) WHERE f_n.fk = k.pk)
And you can turn it into a DELETE pretty easily. But a large delete could hold a lot of locks, so you might want to put this in a table and then delete in batches - a batch shouldn't fail unless a record got linked.
For this to be efficient, you really need to have indexes on the FK columns in the related tables.
You can also do this with left joins, but then you (sometimes) have to de-dupe with a DISTINCT or GROUP BY and the execution plan isn't really usually any better and it's not as conducive to code-generation:
SELECT k.*
FROM k WITH(NOLOCK)
LEFT JOIN f_1 WITH(NOLOCK) ON f_1.fk = k.pk
LEFT JOIN f_2 WITH(NOLOCK) ON f_2.fk = k.pk
...
LEFT JOIN f_n WITH(NOLOCK) ON f_n.fk = k.pk
WHERE k.Active = 0
AND f_1.fk IS NULL
AND f_2.fk IS NULL
...
AND f_n.fk IS NULL
Let us we have parent table with the name Parent and it has at "id" field of any type and an "Active" field of the type bit. We have also a second Child table with his own "id" field and "fk" field which is the reference to the "id" field of the Parent table. Then you can use following statement:
DELETE Parent
FROM Parent AS p LEFT OUTER JOIN Child AS c ON p.id=c.fk
WHERE c.id IS NULL AND p.Active=0
Slightly confused about your question. But you can do a LeftOuterJoin from your main table, To a table that it should supposedly have a foreign key. You can then use a Where statement to check for null values inside the connecting table.
Check here for outer joins : http://en.wikipedia.org/wiki/Join_%28SQL%29#Left_outer_join
You should also write up triggers to do all this for you when a record is deleted or set to false etc.