MYSQL如何映射这些联接结果?

时间:2019-06-19 15:31:24

标签: mysql

我有这些表:

Objects
ID | Name
----------
1    name1

Tags
ID | ObjectId | Tag
--------------------
1    1          tag1
2    1          tag2

Attributes
ID | ObjectId | Key | Value
--------------------
1    1          key1  value1  
2    1          key2  value2

我想检索这些值并将它们映射到我的应用程序代码中的单个对象中。像这样:

id: 1,
name: name1,
tags: [tag=tag1, tag=tag2],
attributes: [{key=key1, value=value1}, {key=key2, value=value2}]

但是,此联接查询无法按我的预期工作:

SELECT      o.id, o.name, t.tag, a.key, a.value 
FROM        objects o 
LEFT JOIN   attributes a on a.ObjectId = o.id
LEFT JOIN   tags t on t.ObjectId = o.id
WHERE       o.id = 1

它给了我这4个结果:

1 | key1 | value1 | tag1
1 | key2 | value2 | tag1
1 | key1 | value1 | tag2
1 | key2 | value2 | tag2

这让我感到惊讶,因为我期望null的一半Attribute和一半Tags的结果。

当我在应用程序代码中映射它时,由于没有办法知道tag1之类的事物是否应该发生多次,所以最终得到重复的值。

我应该如何查询这些数据,以便可以在应用程序代码中映射到这样的对象?

2 个答案:

答案 0 :(得分:1)

您可以使用GROUP_CONCAT()获得所需的内容。使用DISTINCT修饰符删除重复项。

SELECT o.id, o.name, 
        GROUP_CONCAT(DISTINCT t.tag) AS tags, 
        GROUP_CONCAT(DISTINCT CONCAT(a.key, '=', a.value)) AS attributes
FROM object AS o
LEFT JOIN   attributes a on a.ObjectId = o.id
LEFT JOIN   tags t on t.ObjectId = o.id
WHERE       o.id = 1

然后您可以在应用程序语言中拆分这些逗号分隔和相等分隔的字符串。

或者您可以使用现有查询,并以应用程序语言合并相关行。

如果输入表中存在重复项,如果您需要结果包含重复项,请与使用GROUP_CONCAT的子查询一起加入:

SELECT o.id, o.name, t.tags, a.attributes
FROM object AS o
LEFT JOIN (
    SELECT ObjectId, GROUP_CONCAT(key, '-', value) AS attributes
    FROM attributes
    GROUP BY ObjectId
) AS a ON a.ObjectId = o.id
LEFT JOIN (
    SELECT ObjectId, GROUP_CONCAT(tag) AS tags
    FROM tags
    GROUP BY OBjectId
) AS t ON a.ObjectId = t.id
WHERE o.id = 1

答案 1 :(得分:0)

MySQL 8及更高版本具有本机JSON支持,因此您可以执行以下操作:

SELECT      o.ID, o.Name, t.tags, a.attributes
FROM        Objects o
LEFT JOIN   (SELECT ObjectId, JSON_ARRAYAGG(Tag) tags FROM Tags GROUP BY ObjectId) t
            ON t.ObjectId = o.ID
LEFT JOIN   (SELECT ObjectId, JSON_OBJECTAGG(`Key`, `Value`) attributes FROM Attributes GROUP BY ObjectId) a
            ON a.ObjectId = o.ID
WHERE       o.ID = 1;

这将导致

| ID  | Name  | tags             | attributes                           |
| --- | ----- | ---------------- | ------------------------------------ |
| 1   | name1 | ["tag1", "tag2"] | {"key1": "value1", "key2": "value2"} |

View on DB Fiddle