我有两个相关的表,如下所示,我需要JOIN来获取所有新的和更新的记录。这些是具有简化表结构的代表性示例。
第一个表是一个项目表,例如'注释'包含所有现有注释以及“新”注释和现有注释的更新。
第二个表包含注释的挂起更改/更新的详细信息。 例如,如果已修改注释,则使用修改克隆该行并且a row被添加到pendingUpdates表中,其中包含原始注释的id,包含更新的行的id以及进行更新的用户。如果添加了新注释,则工作流程类似,期望原始id和修改后的id引用同一行。
Notes:
+----+---------------------+----------------------------+
| id | title | text |
+----+---------------------+----------------------------+
| 1 | this is a test note | blah blah blah |
| 2 | note 2 | sdfsadfasdf |
| 3 | note 3 | jklhjklhjklhjk |
| 4 | note 3 | This is an update to note3 |
| 5 | note 3 | another update |
| 6 | note 4 | new note |
+----+---------------------+----------------------------+
pendingUpdates:
+----+------------+---------+------+
| id | originalId | cloneId | user |
+----+------------+---------+------+
| 1 | 3 | 4 | 1 |
| 2 | 3 | 5 | 1 |
| 3 | 6 | 6 | 2 |
+----+------------+---------+------+
我想要做的是运行一个SELECT来获取所有Notes并包括该笔记是否有更改(包含更新列表)和任何新笔记。
因此,上面的示例将返回第1,2,3行和第6行。第3行也会将4,5列为更新。
期望结果的示例:
+----+------------+-------------+------+--------+---------------------+
| id | hasChanges | isNewRecord | p_id | clones | title |
+----+------------+-------------+------+--------+---------------------+
| 1 | no | no | NULL | NULL | this is a test note |
| 2 | no | no | NULL | NULL | note 2 |
| 3 | yes | no | 1 | 4,5 | note 3 |
| 6 | yes | yes | 3 | 6 | note 4 |
+----+------------+-------------+------+--------+---------------------+
我尝试了很多不同的查询组合,但还没有得到我需要的内容。 这是我所拥有的非常接近,但包括第4行和第4行。我不想要的结果集中有5个。
SELECT
o.id,
if(o.id = p.originalId, 'yes', 'no') AS hasChanges,
if(p.cloneId = p.originalId,
'yes',
'no') AS isNewRecord,
p.id AS p_id,
group_concat(p.cloneId
separator ',') AS clones,
o.title
FROM
`notes` AS o
LEFT JOIN
`pendingUpdates` AS p ON (o.id = p.originalId)
group by id;
返回:
+----+------------+-------------+------+--------+---------------------+
| id | hasChanges | isNewRecord | p_id | clones | title |
+----+------------+-------------+------+--------+---------------------+
| 1 | no | no | NULL | NULL | this is a test note |
| 2 | no | no | NULL | NULL | note 2 |
| 3 | yes | no | 1 | 4,5 | note 3 |
->| 4 | no | no | NULL | NULL | note 3 |
->| 5 | no | no | NULL | NULL | note 3 |
| 6 | yes | yes | 3 | 6 | note 4 |
+----+------------+-------------+------+--------+---------------------+
这是我最终使用的最终解决方案,它与fthiella的最相似。
再次感谢所有为此提供帮助的人。
SELECT
m.id,
if(m.max_pending IS NOT NULL, 'yes', 'no') hasChanges,
if(m.id = pendingUpdates.cloneId, 'yes', 'no') isNew,
m.clones,
m.pendingIds,
m.title
FROM (SELECT
Notes.id,
MAX(pendingUpdates.id) max_pending,
GROUP_CONCAT(pendingUpdates.id) pendingIds,
GROUP_CONCAT(pendingUpdates.cloneId) clones,
MAX(title) title
FROM Notes
LEFT JOIN pendingUpdates ON Notes.id = pendingUpdates.originalId
GROUP BY Notes.id
) m
LEFT JOIN pendingUpdates ON m.max_pending = pendingUpdates.id
WHERE
m.id NOT IN (SELECT
cloneId
FROM pendingUpdates
WHERE cloneId NOT IN (SELECT
originalId
FROM pendingUpdates)
)
order by id;
答案 0 :(得分:1)
你可以寻找这个
SELECT
o.id,
if(o.id = p.originalId , 'yes', 'no') AS hasChanges,
if(p.cloneId = p.originalId,
'yes',
'no') AS isNewRecord,
p.id AS p_id,
group_concat(p.cloneId
separator ',') AS clones,
o.title
FROM
`notes` AS o
LEFT JOIN
`pendingUpdates` AS p ON (o.id = p.originalId)
where o.id in (select originalId from pendingUpdates)
or o.id in (select id from pendingUpdates)
group by id;
答案 1 :(得分:0)
我已经以这种方式重写了您的查询(您的原始查询使用了一些非聚合列,并且在某些情况下这些列的值可能未确定):
SELECT
m.id,
CASE WHEN m.max_pending IS NOT NULL
THEN 'yes' ELSE 'no' END hasChanges,
CASE WHEN m.id=pendingUpdates.cloneId
THEN 'yes' ELSE 'no' END isNew,
m.min_pending pid,
m.clones,
m.title
FROM (
SELECT
Notes.id,
MAX(pendingUpdates.id) max_pending,
MIN(pendingUpdates.id) min_pending,
GROUP_CONCAT(pendingUpdates.cloneId) clones,
MAX(title) title
FROM
Notes LEFT JOIN pendingUpdates
ON Notes.id = pendingUpdates.originalId
GROUP BY
Notes.id) m LEFT JOIN pendingUpdates
ON m.max_pending = pendingUpdates.id
WHERE
m.id NOT IN (SELECT cloneId FROM pendingUpdates
WHERE cloneId NOT IN (SELECT originalId FROM pendingUpdates))
请参阅小提琴here。