PHP + SQL, 更正tre与父子类别和项目
PHP + SQL, correct tre with parent and child category and item
我正在尝试显示正确的数据树,但我是,股票,所以我希望有人能给我指明正确的方向。
我已经用 PHP 代码和纯 SQL 代码都试过了,让我先展示一下到目前为止我试过的东西。
public function supported($ids) {
$arr = json_decode($ids, true);
$STH = $this->dbh->query("SELECT cid,device FROM supported_devices WHERE id IN (".implode(',',$arr).")");
$a = $STH->fetchAll();
if(count($a)) {
foreach($a as $b) {
$newArr[] = $b['cid'];
}
$STH = $this->dbh->query("SELECT cid,cat_name FROM supported_devices_cats WHERE id IN (".implode(',',$newArr).")");
$c = $STH->fetchAll();
foreach($c as $d) {
$newArr2[] = $d['cid'];
}
$STH = $this->dbh->query("SELECT cat_name FROM supported_devices_cats WHERE id IN (".implode(',',$newArr2).")");
$e = $STH->fetchAll();
foreach($e as $parent) {
$return[] = $parent['cat_name'];
foreach($c as $child) {
$return[] = $child['cat_name'];
foreach($a as $device) {
$return[] = $device['device'];
}
}
}
return $return;
} else {
return array();
}
}
SELECT DISTINCT c.*
FROM supported_devices_cats c
LEFT JOIN supported_devices_cats pc
ON c.id = pc.cid
WHERE
c.cid IS NOT NULL
OR (c.cid IS NULL
AND pc.cid IS NULL)
我正在尝试先显示父类别,然后是所有子类别,然后是每个子类别下正确的设备。我不确定我还能怎么解释它,我添加了一张彩绘图片,也许这能更好地解释我正在尝试做的事情。
更新,我需要将我的MySQL服务器升级到更高版本。
我不太确定您为什么需要 table supported_devices 中的列“cid”。只需 id 就可以作为外键。
话虽如此,这是我用作数据库模式和测试内容的内容:
CREATE DATABASE cats_devs;
USE cats_devs
CREATE TABLE supported_devices_cats(
id INT PRIMARY KEY,
cid INT NULL DEFAULT NULL,
FOREIGN KEY(cid) REFERENCES supported_devices_cats(id),
cat_name VARCHAR(64) NOT NULL,
dt DATETIME NOT NULL DEFAULT NOW()
);
CREATE TABLE supported_devices(
id INT,
FOREIGN KEY(id) REFERENCES supported_devices_cats(id),
device VARCHAR(128) NOT NULL,
dt DATETIME NOT NULL DEFAULT NOW()
);
INSERT INTO supported_devices_cats(id, cid, cat_name) VALUES
(1, NULL, "Disk Drives"), (2, NULL, "Monitors"),
(3, 1, "SSD"), (4, 1, "HDD"),
(5, 2, "TN"), (6, 2, "IPS");
INSERT INTO supported_devices(id, device) VALUES
(4, "Seagate 2TB"), (4, "WD 2TB"),
(3, "Corsair 256GB"), (3, "WD 256GB"),
(5, "ASUS 27in"), (5, "ASUS 21in"),
(6, "Viewsonic 27in"), (6, "LG 24in");
我接下来要做的是 CTE 递归查询(在较新的 MySQL/MariaDB 服务器中可用 - 对于旧版本,将需要与 SELF JOIN 等效的):
WITH RECURSIVE hier_query(id, cat_id, cat_name, dev_name, dt) AS(
SELECT id, cid, cat_name, CAST(NULL AS VARCHAR(128)), dt
FROM supported_devices_cats
WHERE cid IS NULL
UNION ALL
SELECT supported_devices_cats.id, supported_devices_cats.cid,
supported_devices_cats.cat_name, supported_devices.device, supported_devices_cats.dt
FROM supported_devices_cats
JOIN hier_query
ON hier_query.id = supported_devices_cats.cid
LEFT JOIN supported_devices ON supported_devices.id = supported_devices_cats.id
)
SELECT id, cat_id, cat_name, dev_name, dt
FROM hier_query;
这将产生以下包含所有必需信息的结果:
+------+--------+-------------+----------------+---------------------+
| id | cat_id | cat_name | dev_name | dt |
+------+--------+-------------+----------------+---------------------+
| 1 | NULL | Disk Drives | NULL | 2020-06-25 07:52:39 |
| 2 | NULL | Monitors | NULL | 2020-06-25 07:52:39 |
| 3 | 1 | SSD | Corsair 256GB | 2020-06-25 07:52:39 |
| 3 | 1 | SSD | WD 256GB | 2020-06-25 07:52:39 |
| 4 | 1 | HDD | Seagate 2TB | 2020-06-25 07:52:39 |
| 4 | 1 | HDD | WD 2TB | 2020-06-25 07:52:39 |
| 5 | 2 | TN | ASUS 27in | 2020-06-25 07:52:39 |
| 5 | 2 | TN | ASUS 21in | 2020-06-25 07:52:39 |
| 6 | 2 | IPS | Viewsonic 27in | 2020-06-25 07:52:39 |
| 6 | 2 | IPS | LG 24in | 2020-06-25 07:52:39 |
+------+--------+-------------+----------------+---------------------+
现在在这个结果中 table 当 dev_name 为 NULL 时,它是父类别。您可以通过这种方式从中获取所有父类别。然后,当您将 id 与 cat_id 进行比较时,对于每个父类别,您都可以找到子类别。终于可以轻松搞定所有设备了
老实说,我曾尝试将其设为“所有 SQL”解决方案,但我很难按照您想要的方式对 table 进行排序。我打赌其他人会做得更好。
P.S。这是排序问题的快速肮脏技巧。我用“->”分隔符在子名称之前连接了主要类别。这样你以后可以很容易地拆分它们。
WITH RECURSIVE hier_query(id, cat_id, cat_name, dev_name, dt) AS(
SELECT id, cid, cat_name, CAST(NULL AS VARCHAR(128)), dt
FROM supported_devices_cats
WHERE cid IS NULL
UNION ALL
SELECT supported_devices_cats.id, supported_devices_cats.cid,
CONCAT(hier_query.cat_name, "->", supported_devices_cats.cat_name),
supported_devices.device, supported_devices_cats.dt
FROM supported_devices_cats
JOIN hier_query
ON hier_query.id = supported_devices_cats.cid
LEFT JOIN supported_devices ON supported_devices.id = supported_devices_cats.id
)
SELECT id, cat_id, cat_name, dev_name, dt
FROM hier_query
ORDER BY cat_name;
产生:
+------+--------+------------------+----------------+---------------------+
| id | cat_id | cat_name | dev_name | dt |
+------+--------+------------------+----------------+---------------------+
| 1 | NULL | Disk Drives | NULL | 2020-06-25 07:52:39 |
| 4 | 1 | Disk Drives->HDD | Seagate 2TB | 2020-06-25 07:52:39 |
| 4 | 1 | Disk Drives->HDD | WD 2TB | 2020-06-25 07:52:39 |
| 3 | 1 | Disk Drives->SSD | Corsair 256GB | 2020-06-25 07:52:39 |
| 3 | 1 | Disk Drives->SSD | WD 256GB | 2020-06-25 07:52:39 |
| 2 | NULL | Monitors | NULL | 2020-06-25 07:52:39 |
| 6 | 2 | Monitors->IPS | Viewsonic 27in | 2020-06-25 07:52:39 |
| 6 | 2 | Monitors->IPS | LG 24in | 2020-06-25 07:52:39 |
| 5 | 2 | Monitors->TN | ASUS 27in | 2020-06-25 07:52:39 |
| 5 | 2 | Monitors->TN | ASUS 21in | 2020-06-25 07:52:39 |
+------+--------+------------------+----------------+---------------------+
您甚至可以添加“WHERE cat_id IS NOT NULL”条件来删除两个无用的行。所有其他行都包含您需要的内容。
我正在尝试显示正确的数据树,但我是,股票,所以我希望有人能给我指明正确的方向。
我已经用 PHP 代码和纯 SQL 代码都试过了,让我先展示一下到目前为止我试过的东西。
public function supported($ids) {
$arr = json_decode($ids, true);
$STH = $this->dbh->query("SELECT cid,device FROM supported_devices WHERE id IN (".implode(',',$arr).")");
$a = $STH->fetchAll();
if(count($a)) {
foreach($a as $b) {
$newArr[] = $b['cid'];
}
$STH = $this->dbh->query("SELECT cid,cat_name FROM supported_devices_cats WHERE id IN (".implode(',',$newArr).")");
$c = $STH->fetchAll();
foreach($c as $d) {
$newArr2[] = $d['cid'];
}
$STH = $this->dbh->query("SELECT cat_name FROM supported_devices_cats WHERE id IN (".implode(',',$newArr2).")");
$e = $STH->fetchAll();
foreach($e as $parent) {
$return[] = $parent['cat_name'];
foreach($c as $child) {
$return[] = $child['cat_name'];
foreach($a as $device) {
$return[] = $device['device'];
}
}
}
return $return;
} else {
return array();
}
}
SELECT DISTINCT c.*
FROM supported_devices_cats c
LEFT JOIN supported_devices_cats pc
ON c.id = pc.cid
WHERE
c.cid IS NOT NULL
OR (c.cid IS NULL
AND pc.cid IS NULL)
我正在尝试先显示父类别,然后是所有子类别,然后是每个子类别下正确的设备。我不确定我还能怎么解释它,我添加了一张彩绘图片,也许这能更好地解释我正在尝试做的事情。
更新,我需要将我的MySQL服务器升级到更高版本。
我不太确定您为什么需要 table supported_devices 中的列“cid”。只需 id 就可以作为外键。
话虽如此,这是我用作数据库模式和测试内容的内容:
CREATE DATABASE cats_devs;
USE cats_devs
CREATE TABLE supported_devices_cats(
id INT PRIMARY KEY,
cid INT NULL DEFAULT NULL,
FOREIGN KEY(cid) REFERENCES supported_devices_cats(id),
cat_name VARCHAR(64) NOT NULL,
dt DATETIME NOT NULL DEFAULT NOW()
);
CREATE TABLE supported_devices(
id INT,
FOREIGN KEY(id) REFERENCES supported_devices_cats(id),
device VARCHAR(128) NOT NULL,
dt DATETIME NOT NULL DEFAULT NOW()
);
INSERT INTO supported_devices_cats(id, cid, cat_name) VALUES
(1, NULL, "Disk Drives"), (2, NULL, "Monitors"),
(3, 1, "SSD"), (4, 1, "HDD"),
(5, 2, "TN"), (6, 2, "IPS");
INSERT INTO supported_devices(id, device) VALUES
(4, "Seagate 2TB"), (4, "WD 2TB"),
(3, "Corsair 256GB"), (3, "WD 256GB"),
(5, "ASUS 27in"), (5, "ASUS 21in"),
(6, "Viewsonic 27in"), (6, "LG 24in");
我接下来要做的是 CTE 递归查询(在较新的 MySQL/MariaDB 服务器中可用 - 对于旧版本,将需要与 SELF JOIN 等效的):
WITH RECURSIVE hier_query(id, cat_id, cat_name, dev_name, dt) AS(
SELECT id, cid, cat_name, CAST(NULL AS VARCHAR(128)), dt
FROM supported_devices_cats
WHERE cid IS NULL
UNION ALL
SELECT supported_devices_cats.id, supported_devices_cats.cid,
supported_devices_cats.cat_name, supported_devices.device, supported_devices_cats.dt
FROM supported_devices_cats
JOIN hier_query
ON hier_query.id = supported_devices_cats.cid
LEFT JOIN supported_devices ON supported_devices.id = supported_devices_cats.id
)
SELECT id, cat_id, cat_name, dev_name, dt
FROM hier_query;
这将产生以下包含所有必需信息的结果:
+------+--------+-------------+----------------+---------------------+
| id | cat_id | cat_name | dev_name | dt |
+------+--------+-------------+----------------+---------------------+
| 1 | NULL | Disk Drives | NULL | 2020-06-25 07:52:39 |
| 2 | NULL | Monitors | NULL | 2020-06-25 07:52:39 |
| 3 | 1 | SSD | Corsair 256GB | 2020-06-25 07:52:39 |
| 3 | 1 | SSD | WD 256GB | 2020-06-25 07:52:39 |
| 4 | 1 | HDD | Seagate 2TB | 2020-06-25 07:52:39 |
| 4 | 1 | HDD | WD 2TB | 2020-06-25 07:52:39 |
| 5 | 2 | TN | ASUS 27in | 2020-06-25 07:52:39 |
| 5 | 2 | TN | ASUS 21in | 2020-06-25 07:52:39 |
| 6 | 2 | IPS | Viewsonic 27in | 2020-06-25 07:52:39 |
| 6 | 2 | IPS | LG 24in | 2020-06-25 07:52:39 |
+------+--------+-------------+----------------+---------------------+
现在在这个结果中 table 当 dev_name 为 NULL 时,它是父类别。您可以通过这种方式从中获取所有父类别。然后,当您将 id 与 cat_id 进行比较时,对于每个父类别,您都可以找到子类别。终于可以轻松搞定所有设备了
老实说,我曾尝试将其设为“所有 SQL”解决方案,但我很难按照您想要的方式对 table 进行排序。我打赌其他人会做得更好。
P.S。这是排序问题的快速肮脏技巧。我用“->”分隔符在子名称之前连接了主要类别。这样你以后可以很容易地拆分它们。
WITH RECURSIVE hier_query(id, cat_id, cat_name, dev_name, dt) AS(
SELECT id, cid, cat_name, CAST(NULL AS VARCHAR(128)), dt
FROM supported_devices_cats
WHERE cid IS NULL
UNION ALL
SELECT supported_devices_cats.id, supported_devices_cats.cid,
CONCAT(hier_query.cat_name, "->", supported_devices_cats.cat_name),
supported_devices.device, supported_devices_cats.dt
FROM supported_devices_cats
JOIN hier_query
ON hier_query.id = supported_devices_cats.cid
LEFT JOIN supported_devices ON supported_devices.id = supported_devices_cats.id
)
SELECT id, cat_id, cat_name, dev_name, dt
FROM hier_query
ORDER BY cat_name;
产生:
+------+--------+------------------+----------------+---------------------+
| id | cat_id | cat_name | dev_name | dt |
+------+--------+------------------+----------------+---------------------+
| 1 | NULL | Disk Drives | NULL | 2020-06-25 07:52:39 |
| 4 | 1 | Disk Drives->HDD | Seagate 2TB | 2020-06-25 07:52:39 |
| 4 | 1 | Disk Drives->HDD | WD 2TB | 2020-06-25 07:52:39 |
| 3 | 1 | Disk Drives->SSD | Corsair 256GB | 2020-06-25 07:52:39 |
| 3 | 1 | Disk Drives->SSD | WD 256GB | 2020-06-25 07:52:39 |
| 2 | NULL | Monitors | NULL | 2020-06-25 07:52:39 |
| 6 | 2 | Monitors->IPS | Viewsonic 27in | 2020-06-25 07:52:39 |
| 6 | 2 | Monitors->IPS | LG 24in | 2020-06-25 07:52:39 |
| 5 | 2 | Monitors->TN | ASUS 27in | 2020-06-25 07:52:39 |
| 5 | 2 | Monitors->TN | ASUS 21in | 2020-06-25 07:52:39 |
+------+--------+------------------+----------------+---------------------+
您甚至可以添加“WHERE cat_id IS NOT NULL”条件来删除两个无用的行。所有其他行都包含您需要的内容。