如何在SQLite3中为一个资源管理两个关闭表

时间:2019-02-04 17:05:55

标签: database-design sqlite

我希望这不太适合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表中获取注释,并构建一个平坦的注释列表,以放入报表的included部分中。 JSON:API输出。

担心的是,这意味着许多SQL查询和手动重建注释的关系。我担心的是,对每个资源执行多个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');

1 个答案:

答案 0 :(得分:1)

这很容易在一条语句中完成-您只需在选定的值中需要几个相关的子查询即可计算喜欢计数和子评论列表列。

注意:由于无论如何您都将其转换为JSON,因此以下内容使用JSON1扩展名,将注释列使用JSON数组保存步骤。如果未启用启用sqlite的设置进行编译,则可以使用group_concat()进行类似操作。

SharedPreferences

产生

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 [] 及其回复主题的评论而不是每个评论,则recursive CTEs会起作用:

post_id

那只是

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;