我希望这不是太具体的SO。我发现它的学习经验。
在高级别我正在写一个JSON:API接口,一个sqlite3的数据库存储用户的意见。随着JSON:API资源的平面列表可以与每个资源提供included
可能重新指向它似乎是自然的使用闭包表来表示意见线程和评论喜欢其他意见的relationships
部分中列出。
我开始与以下几点:
CREATE TABLE comments (
id INTEGER PRIMARY KEY,
author TEXT,
body TEXT,
created_at DATE,
email TEXT,
href TEXT,
ip_address TEXT,
post_id TEXT
);
CREATE TABLE comment_threads (
parent_id INTEGER NOT NULL,
child_id INTEGER NOT NULL,
PRIMARY KEY (parent_id, child_id)
);
CREATE TABLE comment_likes (
comment_id INTEGER NOT NULL,
ip_address TEXT NOT NULL,
PRIMARY KEY (comment_id, ip_address)
);
我的想法是,我可以选择由post_id
的意见,然后从comment_thread
表抢了意见,并打造出评论的平面列表装进JSON的included
部分:API输出。
令人担忧的是,这意味着许多SQL查询和手动重建的意见的关系。我担心的是,这似乎有点幼稚执行多个SQL查询每个资源。
如何(或可我)在一个(或更少)的SQL语句(S)执行此?
我已经能够使用注释喜欢来实现:
SELECT c.id,c.author,c.body,c.created_at,c.href,c.post_id,
COUNT(cl.comment_id) AS likes
FROM comments AS c
JOIN comment_likes AS cl ON c.id == cl.comment_id
WHERE c.post_id == 'test'
ORDER BY c.created_at ASC;
但我不确定我怎么能扩展为使表如下所示:
| id | author | body | created_at | href | post_id | likes | comments |
|====|========|=================|============|======|=========|=======|============|
| 1 | Bob | test comment | 1990-12-17 | | test | 1 | array(2,3) |
| 2 | Jane | test comment 2 | 1990-12-18 | | | 0 | array() |
| 3 | Jill | test comment 3 | 1990-12-19 | | | 0 | array(4,5) |
| 4 | Bortus | test comment 4 | 1990-12-20 | | | 2 | array() |
| 5 | John | test comment 5 | 1990-12-21 | | | 0 | array() |
这甚至可能吗?
INSERT INTO comments VALUES (1,'Bob','test comment','1990-12-17','[email protected]',NULL,'1.1.1.1','test');
INSERT INTO comments VALUES (2,'Jane','test comment 2','1990-12-18','[email protected]',NULL,'1.1.1.2',NULL);
INSERT INTO comments VALUES (3,'Jill','test comment 3','1990-12-19','[email protected]',NULL,'1.1.1.3',NULL);
INSERT INTO comments VALUES (4,'Bortus','test comment 4','1990-12-20','[email protected]',NULL,'1.1.1.4',NULL);
INSERT INTO comments VALUES (5,'John','test comment 5','1990-12-21','[email protected]',NULL,'1.1.1.5',NULL);
INSERT INTO comments VALUES (6,'Spock','test comment 6','1990-12-22','[email protected]',NULL,'1.1.1.6','test2');
INSERT INTO comments VALUES (7,'Jim','test comment 7','1990-12-23','[email protected]',NULL,'1.1.1.7',NULL);
INSERT INTO comments VALUES (8,'Beverly','test comment 8','1990-12-24','[email protected]',NULL,'1.1.1.8',NULL);
INSERT INTO comments VALUES (9,'Stacy','test comment 9','1990-12-25','[email protected]',NULL,'1.1.1.9',NULL);
INSERT INTO comments VALUES (10,'Alice','test comment 10','1990-12-26','[email protected]',NULL,'1.1.1.10',NULL);
INSERT INTO comment_threads VALUES (1, 2);
INSERT INTO comment_threads VALUES (1, 3);
INSERT INTO comment_threads VALUES (3, 4);
INSERT INTO comment_threads VALUES (3, 5);
INSERT INTO comment_threads VALUES (6, 7);
INSERT INTO comment_threads VALUES (7, 8);
INSERT INTO comment_threads VALUES (8, 9);
INSERT INTO comment_threads VALUES (9, 10);
INSERT INTO comment_likes VALUES (1, '1.1.1.1');
INSERT INTO comment_likes VALUES (4, '1.1.1.2');
INSERT INTO comment_likes VALUES (4, '1.1.1.5');
INSERT INTO comment_likes VALUES (6, '1.1.1.1');
INSERT INTO comment_likes VALUES (6, '1.1.1.4');
INSERT INTO comment_likes VALUES (8, '1.1.1.1');
这是很容易在一个语句来完成 - 你只需要一对夫妇的相关子查询中正在选择用来计算像计数和孩子意见表列中的值。
注意:既然你变成JSON这个反正,下面使用JSON阵列的意见栏保存步骤,使用JSON1扩展。如果你的sqlite的安装程序没有与启用编译的,你可以用group_concat()类似的东西。
SELECT id, author, body, created_at, href, post_id
, (SELECT count(*) FROM comment_likes AS l WHERE c.id = l.comment_id) AS likes
, (SELECT json_group_array(t.child_id) FROM comment_threads AS t WHERE c.id = t.parent_id) AS comments
FROM comments AS c
ORDER BY created_at;
产生
id author body created_at href post_id likes comments
---------- ---------- ------------ ---------- ---------- ---------- ---------- ----------
1 Bob test comment 1990-12-17 test 1 [2,3]
2 Jane test comment 1990-12-18 0 []
3 Jill test comment 1990-12-19 0 [4,5]
4 Bortus test comment 1990-12-20 2 []
5 John test comment 1990-12-21 0 []
6 Spock test comment 1990-12-22 test2 2 [7]
7 Jim test comment 1990-12-23 0 [8]
8 Beverly test comment 1990-12-24 1 [9]
9 Stacy test comment 1990-12-25 0 [10]
10 Alice test comment 1990-12-26 0 []
编辑:如果你想只是一个特定的post_id
和答复线程,而不是每一个评论,评论recursive CTEs开始发挥作用:
WITH one_thread AS
(SELECT id, author, body, created_at, href, post_id FROM comments WHERE post_id = 'test'
UNION ALL
SELECT c.id, c.author, c.body, c.created_at, c.href, c.post_id
FROM one_thread AS o
JOIN comment_threads AS t ON o.id = t.parent_id
JOIN comments AS c ON t.child_id = c.id)
SELECT id, author, body, created_at, href, post_id
, (SELECT count(*) FROM comment_likes AS l WHERE c.id = l.comment_id) AS likes
, (SELECT json_group_array(t.child_id) FROM comment_threads AS t WHERE c.id = t.parent_id) AS comments
FROM one_thread AS c
ORDER BY created_at;
这让刚
id author body created_at href post_id likes comments
---------- ---------- ------------ ---------- ---------- ---------- ---------- ----------
1 Bob test comment 1990-12-17 test 1 [2,3]
2 Jane test comment 1990-12-18 0 []
3 Jill test comment 1990-12-19 0 [4,5]
4 Bortus test comment 1990-12-20 2 []
5 John test comment 1990-12-21 0 []