【问题标题】:How do I manage two closure tables for one resource in SQLite3如何在 SQLite3 中为一个资源管理两个闭包表
【发布时间】:2019-06-28 11:30:47
【问题描述】:

我希望这对于 SO 来说不是太具体。我觉得这是一种学习体验。

在高层次上,我正在为 sqlite3 数据库编写一个 JSON:API 接口,用于存储用户 cmets。使用 JSON:API 可以在 included 部分列出资源的平面列表,每个资源都提供一个 relationships 可以指向其他 cmets,使用闭包表来表示评论线程和评论喜欢似乎很自然。

我从以下开始:

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 选择 cmets,然后从 comment_thread 表中获取 cmets,并构建一个平面的 cmets 列表以放入 JSON:API 输出的 included 部分。

担心的是这意味着许多 SQL 查询和手动重建 cmets 的关系。我担心的是,为每个资源执行多个 SQL 查询似乎有点幼稚。

我如何(或可以我)在一个(或更少的)SQL 语句中执行此操作?

我已经能够通过喜欢使用的评论来完成此操作:

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','foo@example.com',NULL,'1.1.1.1','test');
INSERT INTO comments VALUES (2,'Jane','test comment 2','1990-12-18','foo2@example.com',NULL,'1.1.1.2',NULL);
INSERT INTO comments VALUES (3,'Jill','test comment 3','1990-12-19','foo3@example.com',NULL,'1.1.1.3',NULL);
INSERT INTO comments VALUES (4,'Bortus','test comment 4','1990-12-20','foo4@example.com',NULL,'1.1.1.4',NULL);
INSERT INTO comments VALUES (5,'John','test comment 5','1990-12-21','foo5@example.com',NULL,'1.1.1.5',NULL);
INSERT INTO comments VALUES (6,'Spock','test comment 6','1990-12-22','foo6@example.com',NULL,'1.1.1.6','test2');
INSERT INTO comments VALUES (7,'Jim','test comment 7','1990-12-23','foo7@example.com',NULL,'1.1.1.7',NULL);
INSERT INTO comments VALUES (8,'Beverly','test comment 8','1990-12-24','foo8@example.com',NULL,'1.1.1.8',NULL);
INSERT INTO comments VALUES (9,'Stacy','test comment 9','1990-12-25','foo9@example.com',NULL,'1.1.1.9',NULL);
INSERT INTO comments VALUES (10,'Alice','test comment 10','1990-12-26','foo10@example.com',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');

【问题讨论】:

  • 您能否提供示例数据来填充您的表(作为插入语句以便于复制和粘贴),这些数据可用于获得您想要的输出?
  • @Shawn 添加了示例数据。

标签: database-design sqlite


【解决方案1】:

这很容易在一个语句中完成 - 您只需要在选择的值中创建几个相关的子查询来计算点赞数和子评论列表列。

注意:由于您无论如何都要将其转换为 JSON,因此下面使用 JSON 数组作为 cmets 列来保存步骤,使用 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           []  

【讨论】:

    猜你喜欢
    • 2012-04-21
    • 2019-10-02
    • 2021-04-10
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多