- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在将数据从一个数据库架构迁移到另一个数据库架构。老人schema 有一个基于邻接表的分类系统,ID、类别和 parent_id。如果一个类别低于一秒,那类别将第二个 ID 作为其父 ID。例如:
+-------------+----------------------+--------+
| category_id | name | parent |
+-------------+----------------------+--------+
| 1 | ELECTRONICS | NULL |
| 2 | TELEVISIONS | 1 |
| 3 | TUBE | 2 |
| 4 | LCD | 2 |
| 5 | PLASMA | 2 |
| 6 | PORTABLE ELECTRONICS | 1 |
| 7 | MP3 PLAYERS | 6 |
| 8 | FLASH | 7 |
| 9 | CD PLAYERS | 6 |
| 10 | 2 WAY RADIOS | 6 |
+-------------+----------------------+--------+
新模式有一个改进的前序树遍历算法:
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
| 7 | MP3 PLAYERS | 11 | 14 |
| 8 | FLASH | 12 | 13 |
| 9 | CD PLAYERS | 15 | 16 |
| 10 | 2 WAY RADIOS | 17 | 18 |
+-------------+----------------------+-----+-----+
示例取自文章 Managing Hierarchical Data in MySQL .
无论如何,我有能力或编写具有递归函数的 php 脚本这会将邻接表迁移到预序树结构。基本上对于每一行,它都会插入一个空白的“rgt”值,看起来对于 child ,将函数递归地应用于他们,保持跟踪计数器的值,然后更新 'rgt' 值。
但我想在纯 SQL 中执行此操作。但是,我所知道的还不够一个立足点。对于初学者,我不知道你是否可以用递归查询,或者是否有其他方法可以做到这一点。
最佳答案
这是我得到的;这是一个示例,可以推广或适应您的情况。
首先我会建立一个邻接表(来自维基百科的语言家族数据):
CREATE TABLE IF NOT EXISTS `language_family_adj_list` (
`language_id` int(11) NOT NULL auto_increment,
`language` varchar(20) NOT NULL,
`parent_id` int(11) default NULL,
PRIMARY KEY (`language_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=41 ;
INSERT INTO `language_family_adj_list` (`language_id`, `language`, `parent_id`) VALUES
(1, 'Finno-Ugric', NULL),
(2, 'Hungarian', 1),
(3, 'Khanty', 1),
(4, 'Mansi', 1),
(5, 'Permic', 1),
(6, 'Mari', 1),
(7, 'Mordvinic', 1),
(8, 'Sami', 1),
(9, 'Baltic-Finnic', 1),
(10, 'Komi', 5),
(11, 'Komi-Permyak', 5),
(12, 'Udmurt', 5),
(13, 'Erzya', 7),
(14, 'Moksha', 7),
(15, 'Western Sami', 8),
(16, 'Eastern Sami', 8),
(17, 'Southern Sami', 15),
(18, 'Umi Sami', 15),
(19, 'Lule Sami', 15),
(20, 'Pite Sami', 15),
(22, 'Northern Sami', 15),
(23, 'Kemi Sami', 16),
(24, 'Inari Sami', 16),
(25, 'Akkala Sami', 16),
(26, 'Kildin Sami', 16),
(27, 'Skolt Sami', 16),
(28, 'Ter Sami', 16),
(29, 'Estonian', 9),
(30, 'Finnish', 9),
(31, 'Ingrian', 9),
(32, 'Karelian', 9),
(33, 'Livonian', 9),
(34, 'Veps', 9),
(35, 'Votic', 9),
(36, 'South Estonian', 29),
(37, 'Voro', 36),
(38, 'Karelian Proper', 32),
(39, 'Lude', 32),
(40, 'Olonets Karelian', 32);
这里有一个查询来演示:
mysql> SELECT t1.language AS lev1, t2.language as lev2, t3.language as lev3, t4.language as lev4, t5.language AS lev5
-> FROM language_family_adj_list AS t1
-> LEFT JOIN language_family_adj_list AS t2 ON t2.parent_id = t1.language_id
-> LEFT JOIN language_family_adj_list AS t3 ON t3.parent_id = t2.language_id
-> LEFT JOIN language_family_adj_list AS t4 ON t4.parent_id = t3.language_id
-> LEFT JOIN language_family_adj_list AS t5 ON t5.parent_id = t4.language_id
-> WHERE t1.parent_id IS NULL
-> ORDER BY t1.language, t2.language, t3.language, t4.language, t5.language;
+-------------+---------------+--------------+------------------+------+
| lev1 | lev2 | lev3 | lev4 | lev5 |
+-------------+---------------+--------------+------------------+------+
| Finno-Ugric | Baltic-Finnic | Estonian | South Estonian | Voro |
| Finno-Ugric | Baltic-Finnic | Finnish | NULL | NULL |
| Finno-Ugric | Baltic-Finnic | Ingrian | NULL | NULL |
| Finno-Ugric | Baltic-Finnic | Karelian | Karelian Proper | NULL |
| Finno-Ugric | Baltic-Finnic | Karelian | Lude | NULL |
| Finno-Ugric | Baltic-Finnic | Karelian | Olonets Karelian | NULL |
| Finno-Ugric | Baltic-Finnic | Livonian | NULL | NULL |
| Finno-Ugric | Baltic-Finnic | Veps | NULL | NULL |
| Finno-Ugric | Baltic-Finnic | Votic | NULL | NULL |
| Finno-Ugric | Hungarian | NULL | NULL | NULL |
| Finno-Ugric | Khanty | NULL | NULL | NULL |
| Finno-Ugric | Mansi | NULL | NULL | NULL |
| Finno-Ugric | Mari | NULL | NULL | NULL |
| Finno-Ugric | Mordvinic | Erzya | NULL | NULL |
| Finno-Ugric | Mordvinic | Moksha | NULL | NULL |
| Finno-Ugric | Permic | Komi | NULL | NULL |
| Finno-Ugric | Permic | Komi-Permyak | NULL | NULL |
| Finno-Ugric | Permic | Udmurt | NULL | NULL |
| Finno-Ugric | Sami | Eastern Sami | Akkala Sami | NULL |
| Finno-Ugric | Sami | Eastern Sami | Inari Sami | NULL |
| Finno-Ugric | Sami | Eastern Sami | Kemi Sami | NULL |
| Finno-Ugric | Sami | Eastern Sami | Kildin Sami | NULL |
| Finno-Ugric | Sami | Eastern Sami | Skolt Sami | NULL |
| Finno-Ugric | Sami | Eastern Sami | Ter Sami | NULL |
| Finno-Ugric | Sami | Western Sami | Lule Sami | NULL |
| Finno-Ugric | Sami | Western Sami | Northern Sami | NULL |
| Finno-Ugric | Sami | Western Sami | Pite Sami | NULL |
| Finno-Ugric | Sami | Western Sami | Southern Sami | NULL |
| Finno-Ugric | Sami | Western Sami | Umi Sami | NULL |
+-------------+---------------+--------------+------------------+------+
29 rows in set (0.00 sec)
所以这是修改后的前序遍历树表模式:
CREATE TABLE language_family_mptt (
language VARCHAR(30) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
) COLLATE utf8;
然后是迁移数据的递归存储过程:
TRUNCATE TABLE language_family_mptt;
SET max_sp_recursion_depth = 255;
DROP PROCEDURE IF EXISTS insert_branches;
DROP PROCEDURE IF EXISTS start_tree;
DELIMITER ~~
CREATE PROCEDURE start_tree()
BEGIN
DECLARE language_field VARCHAR(100);
DECLARE done INT DEFAULT 0;
DECLARE insert_id INT;
DECLARE source_id INT;
DECLARE cursor1 CURSOR FOR SELECT language, language_id FROM language_family_adj_list WHERE parent_id IS NULL ORDER BY language;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cursor1;
read_loop: LOOP
SET @my_left = 1;
FETCH cursor1 INTO language_field, source_id;
INSERT INTO language_family_mptt ( language, lft ) VALUES ( language_field, 1 );
CALL insert_branches( source_id );
UPDATE language_family_mptt SET rgt = @my_left + 1 WHERE lft = 1 AND rgt = 0;
IF done THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE cursor1;
END; ~~
CREATE PROCEDURE insert_branches( IN source_parent_id INT )
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE next_source_parent_id INT DEFAULT NULL;
DECLARE orig_left INT DEFAULT NULL;
DECLARE language_field VARCHAR(100);
DECLARE cursor1 CURSOR FOR SELECT language_id, language FROM language_family_adj_list WHERE parent_id = source_parent_id ORDER BY language;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cursor1;
read_loop: LOOP
FETCH cursor1 INTO next_source_parent_id, language_field;
IF done THEN
LEAVE read_loop;
END IF;
SET @my_left = @my_left + 1;
INSERT INTO language_family_mptt ( language, lft ) VALUES ( language_field, @my_left );
SET orig_left = @my_left;
CALL insert_branches( next_source_parent_id );
UPDATE language_family_mptt SET rgt = @my_left + 1 WHERE lft = orig_left AND rgt = 0 ;
SET @my_left = @my_left + 1;
END LOOP;
CLOSE cursor1;
END; ~~
DELIMITER ;
结果如下:
mysql> SELECT CONCAT( REPEAT( ' ', (COUNT(parent.language) - 1) ), node.language) AS name FROM language_family_mptt AS node, language_family_mptt AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.language ORDER BY node.lft;
+---------------------------------+
| name |
+---------------------------------+
| Finno-Ugric |
| Baltic-Finnic |
| Estonian |
| South Estonian |
| Voro |
| Finnish |
| Ingrian |
| Karelian |
| Karelian Proper |
| Lude |
| Olonets Karelian |
| Livonian |
| Veps |
| Votic |
| Hungarian |
| Khanty |
| Mansi |
| Mari |
| Mordvinic |
| Erzya |
| Moksha |
| Permic |
| Komi |
| Komi-Permyak |
| Udmurt |
| Sami |
| Eastern Sami |
| Akkala Sami |
| Inari Sami |
| Kemi Sami |
| Kildin Sami |
| Skolt Sami |
| Ter Sami |
| Western Sami |
| Lule Sami |
| Northern Sami |
| Pite Sami |
| Southern Sami |
| Umi Sami |
+---------------------------------+
39 rows in set (0.00 sec)
:D
关于algorithm - 递归查询邻接表以在 SQL 中预先排序树遍历?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5508985/
我正在尝试对每个条目有多个值的关联数组进行排序。 例如 [0] => stdClass Object ( [type] => node [sid] => 158 [score] => 0.059600
我在 mysql 中有“日期”列以这种格式保存日期 2014 年 9 月 17 日(日-月-年) 我需要对它们进行升序排序,所以我使用了这个命令: SELECT * FROM table ORDER
我目前正在将 MySQL 存储过程重写为 MS SQL 存储过程,但遇到了问题。 在 MySQL 存储过程中,有一个游标,它根据最近的日期 (effdate) 选择一个值并将其放入变量 (thestt
我想要 gwt r.QuestionId- 排序。但是我得到未排序的 QuestionId 尽管我提到了 QuestionId ASC 的顺序。 SELECT r.QuestionId,
我有一个关于在 scandir 函数中排序的基本问题。到目前为止,我阅读了 POSIX readdir 的手册页,但没有找到有关订购保证的具体信息。 但是当我遍历大目录(无法更改,只读)时,我在多个系
基本上我必须从 SQL 数据库中构建项目列表,但是用户可以选择对 7 个过滤器的任意组合进行过滤,也可以选择要排序的列以及按方向排序。 正如您可以想象的那样,这会以大量不同的组合进行编码,并且数据集非
我有两张 table 。想象第一个是一个目录,包含很多文件(第二个表)。 第二个表(文件)包含修改日期。 现在,我想选择所有目录并按修改日期 ASC 对它们进行排序(因此,最新的修改最上面)。我不想显
我想先根据用户的状态然后根据用户名来排序我的 sql 请求。该状态由 user_type 列设置: 1=活跃,2=不活跃,3=创始人。 我会使用此请求来执行此操作,但它不起作用,因为我想在“活跃”成员
在 C++ 中,我必须实现一个“类似 Excel/Access”(引用)的查询生成器,以允许对数据集进行自定义排序。如果您在 Excel 中使用查询构建器或 SQL 中的“ORDER BY a, b,
我面临这样的挑战: 检索按字段 A 排序的文档 如果字段 B 存在/不为空 . 否则 按字段排序 C. 在 SQL 世界中,我会做两个查询并创建一个 UNION SELECT,但我不知道如何从 Mon
我想对源列表执行以下操作: map 列表 排序 折叠 排序 展开 列表 其中一些方法(例如map和toList)是可链接的,因为它们返回非空对象。但是,sort 方法返回 void,因为它对 List
我制作了一个用于分析 Windows 日志消息编号的脚本。 uniq -c 数字的输出很难预测,因为根据数字的大小会有不同的空白。此时,我手动删除了空白。 这是对消息进行排序和计数的命令: cat n
我有以下词典: mydict1 = {1: 11, 2: 4, 5: 1, 6: 1} mydict2 = {1: 1, 5: 1} 对于它们中的每一个,我想首先按值(降序)排序,然后按键(升序)排序
我刚刚开始使用泛型,目前在对多个字段进行排序时遇到问题。 案例: 我有一个 PeopleList 作为 TObjectList我希望能够通过一次选择一个排序字段,但尽可能保留以前的排序来制作类似 Ex
有没有办法在 sql 中组合 ORDER BY 和 IS NULL 以便我可以在列不为空时按列排序,但如果它为null,按另一列排序? 最佳答案 类似于: ORDER BY CASE WHEN
我有一个包含 2 列“id”和“name”的表。 id 是常规的自动增量索引,name 只是 varchar。 id name 1 john 2 mary 3 pop 4 mary 5 j
场景 网站页面有一个带有分页、过滤、排序功能的表格 View 。 表中的数据是从REST API服务器获取的,数据包含数百万条记录。 数据库 REST API 服务器 Web 服务器 浏览器 问
假设我有一本字典,其中的键(单词)和值(分数)如下: GOD 8 DONG 16 DOG 8 XI 21 我想创建一个字典键(单词)的 NSArray,首先按分数排序,然后按字
如何在 sphinx 上通过 sql 命令选择前 20 行按标题 WEIGHT 排序,接下来 20 行按标题 ASC 排序(总共 40 个结果),但不要给出重复的标题输出。 我尝试了这个 sql 命令
我有一个奇怪的问题,当从 SQLite 数据库中选择信息并根据日期排序时,返回的结果无效。 我的SQL语句是这样的: Select pk from usersDates order by dateti
我是一名优秀的程序员,十分优秀!