MySQL - MyISAM multi-table delete (similar to ON CASCADE DELETE) - myisam

I'm looking to delete all entries that are referenced by a record, and all the children in different tables as well. If possible I'd like to use a multi-table delete statement as opposed to triggers.
For example
Table: forms
id var
1 foo
2 bar
Table 2: form_options
id form_id var
1 1 blah
2 2 hello
3 2 world
Table 3: form_options_info
id form_options_id var
1 3 world info
So given the above type of table struct, if I delete row 2 from forms that would delete row 2,3 from form_options as well as row 1 from form_options_info.

Maybee not the best solution, but it works:
DELETE FROM form_options_info, form_options, forms
USING forms INNER JOIN form_options INNER JOIN form_options_info
WHERE (form_options_info.form_options_id = form_options.id
AND form_options.form_id = forms.id
OR form_options.form_id = forms.id)
AND forms.id = 2;
...or just change the tables to InnoDB ;-)...

Related

Common Table Expression in sqlite using rowid

I found a good article on converting adjacency to nested sets at http://dataeducation.com/the-hidden-costs-of-insert-exec/
The SQL language used is Microsoft SQL Server (I think) and I am trying to convert the examples given in the article to sqlite (as this is what I have easy access to on my Macbook).
The problem I appear to be having is converting the part of the overall CTE query to do with the Employee Rows
EmployeeRows AS
(
SELECT
EmployeeLevels.*,
ROW_NUMBER() OVER (ORDER BY thePath) AS Row
FROM EmployeeLevels
)
I converted this to
EmployeeRows AS
(
SELECT
EmployeeLevels.*,
rowid AS Row
FROM EmployeeLevels
ORDER BY thePath
)
and the CTE query runs (no syntax errors) but the output I get is a table without the Row and Lft and Rgt columns populated
ProductName ProductID ParentProductID TreePath HLevel Row Lft Rgt
----------- ---------- --------------- ---------- ---------- ---------- ---------- ----------
Baby Goods 0 0 1
Baby Food 10 0 0.10 2
All Ages Ba 100 10 0.10.100 3
Strawberry 200 100 0.10.100.2 4
Baby Cereal 250 100 0.10.100.2 4
Beginners 150 10 0.10.150 3
Formula Mil 300 150 0.10.150.3 4
Heinz Formu 310 300 0.10.150.3 5
Nappies 20 0 0.20 2
Small Pack 400 20 0.20.400 3
Bulk Pack N 450 20 0.20.450 3
I think the start of the problem is the Row is not getting populated and therefore the Lft and Rgt columns do not get populated by the following parts of the query.
Are there any sqlite experts out there to tell me:
am I translating the rowid part of the query correctly
does sqlite support a rowid in a part of a CTE query
is there a better way? :)
Any help appreciated :)
am I translating the rowid part of the query correctly
No.
The SQL:
SELECT
EmployeeLevels.*,
rowid AS Row
FROM EmployeeLevels
ORDER BY thePath
has the Row defined as the rowid of table EmployeeLevels in SQLite, ignoring the order clause. Which is different from the intention of ROW_NUMBER() OVER (ORDER BY thePath) AS Row
does sqlite support a rowid in a part of a CTE query
Unfortunately no. I assume you mean this:
WITH foo AS (
SELECT * FROM bar ORDER BY col_a
)
SELECT rowid, *
FROM foo
but SQLite will report no such column of rowid in foo.
is there a better way?
Not sure it is better but at least it works. In SQLite, you have a mechanism of temp table which exists as long as your connection opens and you didn't delete it deliberately. Rewrite the above SQL in my example:
CREATE TEMP TABLE foo AS
SELECT * FROM bar ORDER BY col_a
;
SELECT rowid, *
FROM foo
;
DROP TABLE foo
;
This one will run without SQLite complaining.
update:
As of SQLite version 3.25.0, window function is supported. Hence you can use row_number() over (order by x) expression in your CTE if you happen to use a newer SQLite

Zipping rows with the same "key" while joining tables

I have two tables, one with objects, one with properties of the objects. Both tables have a personal ID and a date as "key", but since multiple orders of objects can be done by one person on a single day, it doesn't match well. I do know however, that the entries are entered in the same order in both tables, so it is possible to join on the order, if the personID and date are the same.
This is what I want to accomplish:
Table 1:
PersonID Date Object
1 20-08-2013 A
2 13-11-2013 B
2 13-11-2013 C
2 13-11-2013 D
3 21-11-2013 E
Table 2:
PersonID Date Property
4 05-05-2013 $
1 20-08-2013 ^
2 13-11-2013 /
2 13-11-2013 *
2 13-11-2013 +
3 21-11-2013 &
Result:
PersonID Date Object Property
4 05-05-2013 $
1 20-08-2013 A ^
2 13-11-2013 B /
2 13-11-2013 C *
2 13-11-2013 D +
3 21-11-2013 E &
So what I want to do, is join the two tables and "zip" the group of entries that have the same (PersonID,Date) "key".
Something called "Slick" seems to have this (see here), but I'd like to do it in SQLite.
Any advice would be amazing!
You are on the right track. Why not just do a LEFT JOIN between the tables like
select t2.PersonID,
t2.Date,
t1.Object,
t2.Property
from table2 t2
left join table1 t1 on t2.PersonID = t1.PersonID
order by t2.PersonID
Use a additional column to make every key unique in both tables. For example in SQLite you could use RowIDs to keep track of the order of insertion. To store this additional column in the database itself might be useful for other queries as well, but you do not have to store this.
First add the column ID to both tables, the DDL queries should now look like this: (make sure you do not add the primary key constraint until both tables are filled.
CREATE TABLE table1 (
ID,
PersonID,
Date,
Object
);
CREATE TABLE table2 (
ID,
PersonID,
Date,
Property
);
Now populate the ID column. You can adjust the ID to your liking. Make sure you do this for table2 as well:
UPDATE table1
SET ID =(
SELECT table1.PersonID || '-' || table1.Date || '-' || count( * )
FROM table1 tB
WHERE table1.RowID >= tB.RowID
AND
table1.PersonID == tB.PersonID
AND
table1.Date == tB.Date
);
Now you can join them:
SELECT t2.PersonID,
t2.Date,
t1.Object,
t2.Property
FROM table2 t2
LEFT JOIN table1 t1
ON t2.ID = t1.ID;

Filtering in Oracle based on a group of values contained in a list of values

I have following two tables:
ID_PERSON NAME
-----------------
1 John
2 Joe
3 Peter
ID_PERSON ID_SPECIALIZATION
------------------------------
1 5
1 6
1 7
2 5
2 1
3 6
3 10
I need to filter data based on group of ids ID_SPECIALIZATION that will be provided. For example
I want to display only those persons who has specialization in 5 and 6 so it will return only first person. In ASP.NET Web form there will be two listboxes, left and right button, in first LB there will be all possible specializations and user will choose some of them to second LB as filtering options. I have no idea how to put this filtering condition in sql query. Thanks for help.
You could use the following:
SQL> SELECT p.id_person, p.NAME
2 FROM person p
3 JOIN person_spe s ON p.id_person = s.id_person
4 WHERE id_specialization IN (5, 6)
5 GROUP BY p.id_person, p.NAME
6 HAVING COUNT(*) = 2;
ID_PERSON NAME
---------- -----
1 John
One way to do it:
SELECT
ID_PERSON
, NAME
FROM
Person AS p
WHERE EXISTS
( SELECT *
FROM
PersonSpecialization AS ps
WHERE ps.ID_PERSON = p.ID_PERSON
AND ps.ID_SPECIALIZATION = 5
)
AND EXISTS
( SELECT *
FROM
PersonSpecialization AS ps
WHERE ps.ID_PERSON = p.ID_PERSON
AND ps.ID_SPECIALIZATION = 6
)
SELECT d1.id_person, d1.name FROM tbl_table1 d1
INNER JOIN tbl_table2 d1
ON d1.ID_PERSON=d2.ID_PERSON
WHERE ID_SPECILIZATION = ?
Theres the query but I'm not sure how asp.net works and passing in the value. It might be work looking up bind variables which allows you to use place holders in the sql which oracle then caches the query and just uses the values that you pass in at run tuime using EXECUTE IMMEDIATE.

Getting an SQL statement to output a table in a certain order

I'm doing a test web shop that has sections within sections. There can be an unlimited number of levels so I have just one table Section.
The table has the following columns:
SectionID, SectionTitle, SectionLevel, ParentID, PageOrder
SectionLevel: 1 being topmost (no parent)
PageOrder: Within it's parent group, which order it should go in.
And for test data :
SectionID SectionTitle SectionLevel ParentID PageOrder
--------- ------------ ------------ -------- ---------
2 Ladies 1 0 2
3 Mens 1 0 3
4 Jewellery 2 2 1
5 Clothing 2 2 2
6 Clothing 2 3 1
7 Accessories 2 3 2
I want to return this data in one table so that the first top level section is first, and then all of it's children's sections are next, and then the second top level section etc.
I've had a play around with it but can't get to come out right. I think that it should be possible to do it if I redesigned the table but can't think how.
The data should come back in the following order:
SectionID SectionTitle SectionLevel ParentID PageOrder
--------- ------------ ------------ -------- ---------
2 Ladies 1 0 2
4 Jewellery 2 2 1
5 Clothing 2 2 2
3 Mens 1 0 3
6 Clothing 2 3 1
7 Accessories 2 3 2
WITH tree (SectionID, ParentID, SectionLevel, SectionTitle) AS
(
SELECT SectionID, ofs.ParentID, ofs.SectionLevel, ofs.SectionTitle
FROM Section ofs
WHERE ofs.ParentID = 0
ORDER BY SectionID
UNION ALL
SELECT SectionID, ofs.ParentID, ofs.SectionLevel, ofs.SectionTitle
FROM Section ofs
JOIN tree ON tree.ID = ofs.ParentID
ORDER BY PageOrder
)
This is deliberately slightly niaive to make it easier on my fingers. It can be tuned if necessary to allow more nodes in the tree to be accomodated.
DECLARE
#maxPageOrder INT,
#maxLevel INT,
#multiplier INT
SELECT
#maxPageOrder = MAX(PageOrder) + 1,
#maxLevel = MAX(SectionLevel)
FROM
Section
SELECT
#multiplier = POWER(#maxPageOrder, #maxLevel - 1)
;
WITH
recursed_tree
AS
(
SELECT
SectionID AS SectionID,
PageOrder * #multiplier AS finalOrder,
#multiplier / #maxPageOrder AS multiplier
FROM
Section
WHERE
ParentID = 0
UNION ALL
SELECT
child.SectionID,
parent.finalOrder + child.PageOrder * parent.multiplier,
parent.multiplier / #maxPageOrder
FROM
recursed_tree AS parent
INNER JOIN
Section AS child
ON child.ParentID = parent.SectionID
)
SELECT
Section.*
FROM
Section
INNER JOIN
recursed_tree
ON Section.SectionID = recursed_tree.SectionID
ORDER BY
recursed_tree.finalOrder
Note: This assumes all page orders start from 1, rather than 0.
Here's the messy solution I was talking about..
select
a.SectionID, a.SectionTitle, a.SectionLevel, a.ParentID, a.PageOrder
from
section a
left outer join section b on b.SectionID=a.ParentID
left outer join section c on c.SectionID=b.ParentID
order by
c.PageOrder, b.PageOrder, a.PageOrder
As I mentioned in the comment, better to do it in code.. this is only for 3 levels (you could make it more by adding another outer join and order by clause).
This is rather complicated in SQL. If you have access to Safari Books, there are some relevant sections in Joe Celko's Trees and Hierarchies in SQL for Smarties.

Parent Child table record - Building SQL query

Here is my table and data of these tables
Table name: Code
CID Code
1 abc
2 def
3 xyz
Table Name : Details
ID Name CID
1 a 1
2 b 2
Resultant Table:
ID Code Name
1 abc a
2 abc Null
3 def b
4 def Null
5 xyz Null
6 xyz Null
I nned to get all record from the code table and against each code I have to get all the rows from the details table, if some code have value their need value and if not then Null
Thanks
Sounds like you're looking for the cartesian product:
SELECT
c.CID * d.ID AS ID,
c.Code,
CASE
WHEN c.CID = d.CID THEN d.Name
ELSE NULL
END AS Name
FROM Code c
CROSS JOIN Details d
Although cartesian products are quite slow for larger tables... so be sure that this is what you really want.

Resources