MySQL request for Node tree - mysql

I have a node tree in a MySQL Base and I want to get result like this
Node_1
Node_1_1
Node_1_1_1
Node_1_1_2
Node_1_2
Node_1_2_1
Node_2
Now I have a query that gives me only one deep child and all rests at the end of a list. ( Node_1_1_2 would be the last in this example )
Here is my code:
SELECT name,
if ( parentId = -1, "Root",
if ( exists( SELECT id FROM citizensTree AS t2 WHERE t1.id = t2.parentId), "Inner", "Leaf")
)
AS type FROM citizensTree as t1
I love this SQL solution:
SELECT t.id, t.name FROM tree t CONNECT BY prioir id = parentId START WITH parentId = -1
But it doesnt work in MySQL

The CONNECT BY is non-standard SQL syntax. It's supported by Oracle and Informix as far as I know, but definitely not MySQL.
MySQL 8.0 supports recursive queries using standard ANSI/ISO SQL syntax. See https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions-recursive-examples
Earlier versions of MySQL do not support this syntax. You can simulate recursive queries using a variety of workarounds. See my answer to What is the most efficient/elegant way to parse a flat table into a tree?

Related

Getting syntax error for WITH RECURSIVE (MySQL 8.0.27 version)

I keep getting a syntax error "WITH is not valid input in this position" for WITH RECURSIVE. I've seen a similar problem here, where people back in 2018 said MySQL will support CTE's in MySQL version 8. Some other sources also refer that CTE should work for MySQL since version 8.0. My current version is 8.0.27, however, I still can't use WITH RECURSIVE in MySQL Workbench.
The query I need to retrieve the family tree is:
WITH RECURSIVE family_path (individual_id, first_name, path) AS
(
SELECT individual_id, first_name, first_name as path
FROM individual
WHERE parent IS NULL
UNION ALL
SELECT c.individual_id, c.first_name, CONCAT(fp.path, ' > ', c.first_name)
FROM family_path AS fp JOIN individual AS c
ON fp.individual_id = c.parent
)
SELECT * FROM family_path
ORDER BY path;
Is there any way for me to solve this problem?

SQLite / MySQL compatibility issue

I know SQL in SQLite is not completely implemented the same way as in MySql. My problem with the following queries is, that they are not compatible and I like to avoid a conditional if <DBMS> ... else
SQLite query
UPDATE sorties SET state = '#'
WHERE `key` IN (
SELECT `key` FROM sorties
INNER JOIN reports AS r
ON r.sortieId=sorties.`key`);
Error on MySQL:
SQL Error (1093): Table 'sorties' is specified twice, both as a target for 'UPDATE' and as a separate source for data
MySQL query (adapted from here)
UPDATE sorties AS s SET s.state='#'
WHERE s.`key` IN (
SELECT t.sortieId FROM (
SELECT r.sortieId AS sortieId
FROM reports AS r
INNER JOIN sorties AS sort
ON sort.`key`=r.sortieId)
AS t);
Error on SQLite:
SQLiteManager: Likely SQL syntax error: UPDATE sorties AS s SET s.state='#'
WHERE s.key IN ( SELECT t.sortieId FROM (
SELECT DISTINCT r.sortieId AS sortieId
FROM reports AS r
INNER JOIN sorties AS sort
ON sort.key=r.sortieId) AS t); [ near "AS": syntax error ]
Exception Name: NS_ERROR_FAILURE
Exception Message: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [mozIStorageConnection.createStatement]
I can't figure out how to make this queries work on both systems equally!
All I want to have is, that each state of sorties must be '#' when it's key can be found in reports.sortieId.
Maybe there is a different approach for this?
Thank you
The first command reads the key value from the sorties table in the subquery, and then checks whether those key values exist in the sorties table in the outer statement. That check is superfluous; you can just compare the values to the ones in reports directly:
UPDATE sorties
SET state = '#'
WHERE key IN (SELECT sortieId
FROM reports);
As for the second command, SQLite does not support aliasing a table used in INSERT/UPDATE/DELETE because those commands work only on a single table. You can just remove the AS s and replace s with sorties everywhere.

UPDATE syntax that works in major databases

I want to update a table (target) based on the values present in another table (source). But I am looking for a syntax that will work in 4 major databases - Oracle, MS SQL Server, PostgreSQL, MySQL.
So far, I am not able to find such a uniform syntax. Have I missed such syntax or there is really no such syntax?
Oracle
UPDATE target t
SET (t.col1, t.col2) = (SELECT s.col1, s.col2
FROM source s
WHERE s.key = t.key)
MS SQL Server / PostgreSQL
UPDATE target t
SET t.col1 = s.col1, t.col2 = s.col2
FROM source s
WHERE t.key=s.key
MySQL
UPDATE target, source
SET t.col1=s.col1, t.col2=s.col2
WHERE s.key=t.key
It is inefficient, but the ANSI SQL Standard way to do this is:
UPDATE target
SET col1 = (SELECT s.col1
FROM source s
WHERE s.key = target.key),
col2 = (SELECT s.col2
FROM source s
WHERE s.key = target.key);
This does not mean to say it will work in every RDBMS (e.g. I don't think it would work in Access), but it does work in the 4 you have listed.
I would personally value performance over portability every day of the week so I would not use this syntax. I would be inclined to use a use a stored-procedure, with a common name, but differing syntax for each RDBMS.
UPDATE
Actually, the method you have shown for Oracle using row value constructors is also allowed by the ANSI SQL Standard:
UPDATE target
SET (t.col1, t.col2) = (SELECT s.col1, s.col2
FROM source s
WHERE s.key = t.key);
Unfortunately, as mentioned above, just because it is in the ANSI Standards it does not mean that it works across platforms.
ANSI update syntax (it should work in DBMS that you listed):
update t1
set col1 = (
select col1
from t2
where t1.key = t2.key
),
set col2 = (
select col2
from t2
where t1.key = t2.key
)

MySQL left join subquery fail

Following query runs well in MySQL 5.x
SELECT
m_area.id, m_area.cn_areaName, m_area.de_areaName,
m_area.en_areaName,m_area.jp_areaName,t_shop.count
FROM
m_area left join
(
select t_shop.areaID, count(areaID) AS count
from t_shop
group by t_shop.areaID
) t_shop
on m_area.id = t_shop.areaID
However, when I have to run it in a 4.0.23 MySQL DB with same DB structure and data it just return following message:
1064 - You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '[
select t_shop.areaID, count(areaID) AS count
from t_s
I tried many times but still failed. Is left join to subquery not allowed in MySQL 4.x ? Then that mean I have to do it with a temp table?
Thanks in advance!
Subqueries were quite not well supported with MySQL 4.0 : it became possible to use them (at least, in some real, useful way) with MySQL 4.1 -- and MySQL 4.0 is really old, now...
See for instance this page of the MySQL manual : 12.2.8. Subquery Syntax (quoting, emphasis mine) :
Starting with MySQL 4.1, all subquery forms and operations that the
SQL standard requires are supported,
as well as a few features that are
MySQL-specific.
With MySQL versions prior to 4.1, it
was necessary to work around or
avoid the use of subqueries. In
many cases, subqueries can
successfully be rewritten using joins
and other methods. See Section
12.2.8.11, “Rewriting Subqueries as Joins for Earlier MySQL Versions”.
take out ", count(areaID) AS count"
The multiple columns in the subquery is messing up the join.
A temp table should work fine ....
Have fun!
Only thing I could think of is adding the tablename to your areaID in the subquery or renaming the reserved word count to cnt.
SELECT m_area.id
, m_area.cn_areaName
, m_area.de_areaName
, m_area.en_areaName
,m_area.jp_areaName
,t_shop.cnt
FROM m_area
left join (
select t_shop.areaID
, count(t_shop.areaID) AS cnt
from t_shop
group by t_shop.areaID
) t_shop on m_area.id = t_shop.areaID

mySQL Nested Query Syntax

I am trying to use a nested query approach to build a query-on-query for my mySQL database and failing to correctly generate output. I am able to import my table into Microsoft Access and build Query1 and then build Query2 on Query1 to get the correct output I'm looking for so I feel like I'm close, I just can't get the right syntax to get the output I'm looking for using a mySQL query approach.
Query1, here is the SQL statement from Access for Query1.
SELECT DISTINCT MediaBuys.DistrictID, MediaBuys.SpenderID, MediaBuys.PG, MediaBuys.SupportType, MediaBuys.PriSupportType
FROM MediaBuys
WHERE MediaBuys.PG ="P";
Query2, if I have built Query1 in Access as above and I run this SQL statement in Access as a separate query built on the first I can generate the output I'm looking for.
SELECT Query1.DistrictID, Query1.SpenderID, Query1.PG, Query1.SupportType, Query1.PriSupportType, Count(Query1.SupportType) AS CountOfSupportType
FROM Query1 INNER JOIN Query1 AS Query1_1 ON Query1.PG = Query1_1.PG AND Query1.SpenderID = Query1_1.SpenderID AND Query1.DistrictID = Query1_1.DistrictID
GROUP BY Query1.DistrictID, Query1.SpenderID, Query1.PG, Query1.SupportType, Query1.PriSupportType
HAVING Count(Query1.SupportType) > 1;
I'd like to be able to produce the same output from a query in mySQL. Since I have the SQL statements of these two queries I feel like this should be doable, I've attempted to build a nested query in a number of different ways and each attempt fails, it seems I can't put together the correct syntax. The most common error I receive is "Error Code: 1146. Table 'Query1' doesn't exist".
Is this doable in mySQL and if so can anyone help me with the correct syntax?
Just like you created the query Query1 in Access, create a view View1 in MySql:
CREATE VIEW View1 AS
SELECT DISTINCT DistrictID, SpenderID, PG, SupportType, PriSupportType
FROM MediaBuys
WHERE PG ='P';
and your query will be:
SELECT
View1.DistrictID, View1.SpenderID, View1.PG, View1.SupportType, View1.PriSupportType,
Count(View1.SupportType) AS CountOfSupportType
FROM View1 INNER JOIN View1 AS View1_1
ON View1.PG = View1_1.PG AND View1.SpenderID = View1_1.SpenderID
AND View1.DistrictID = View1_1.DistrictID
GROUP BY View1.DistrictID, View1.SpenderID, View1.PG, View1.SupportType, View1.PriSupportType
HAVING Count(View1.SupportType) > 1;