如果子查询在 MySQL 中返回多于 1 行,如何将 JSON 放入列数据中

Posted

技术标签:

【中文标题】如果子查询在 MySQL 中返回多于 1 行,如何将 JSON 放入列数据中【英文标题】:How to put JSON into a column data if sub-query returns more than 1 row in MySQL 【发布时间】:2016-07-20 21:21:44 【问题描述】:

我想使用与选择用户相同的查询来选择用户组合。

这是我想要的示例。

用户表

----------------------------------------------------------------------
UID     NAME        USERNAME        EMAIL       PASSWORD        STATUS
----------------------------------------------------------------------
1       Manoj       manoj           a@a.com     ********        1
2       Test U      testing         b@a.com     ********        1
3       Company     user            c@a.com     ********        1
4       Agency      company         d@a.com     ********        1

我的数据库中的用户表

投资组合表

-----------------------------------
PID     UID     TITLE       STATUS
-----------------------------------
1       1       title 1     1
2       1       title 2     1
3       1       title 3     1
4       2       title 1     1

我的数据库中的投资组合表 我想要的结果

----------------------------------
UID     USERNAME        PORTFOLIO
----------------------------------
1       manoj           JSON OBJECT OF PID (1,2,3)
2       testing         JOSN OBJECT OF PID (4)
3       user            NULL
4       company         NULL

目前我正在尝试使用

SELECT u.uid,u.username,(SELECT * FROM portfolio p WHERE u.UID=p.UID) as portfolio FROM users u

这个问题有解决办法吗?

【问题讨论】:

【参考方案1】:

有点复杂,但您可以为每一行创建 JSON 对象,使用 GROUP_CONCAT 连接它们并将结果(包装在 [] 中以使其成为数组)转换为 JSON;

SELECT u.uid, u.username, 
  CASE WHEN p.uid IS NULL 
       THEN NULL 
       ELSE CAST(CONCAT('[',
                   GROUP_CONCAT(JSON_OBJECT('pid', p.pid,
                                            'title', p.title, 
                                            'status', p.status)),     
                 ']') AS JSON) END portfolios
FROM user u
LEFT JOIN portfolio p
  ON u.uid=p.uid
WHERE p.status = 1
GROUP BY u.uid, u.username;

...这给...

+------+----------+-----------------------------------------------------------------------------------------------------------------------------------------+
|    1 | manoj    | ["pid": 1, "title": "title 1", "status": 1, "pid": 2, "title": "title 2", "status": 1, "pid": 3, "title": "title 3", "status": 1] |
|    2 | testing  | ["pid": 4, "title": "title 1", "status": 1]                                                                                           |
|    3 | user     | NULL                                                                                                                                    |
|    4 | company  | NULL                                                                                                                                    |
+------+----------+-----------------------------------------------------------------------------------------------------------------------------------------+

如果您使用的是不支持 JSON 的旧版 mysql,您可以将其构建为字符串;

SELECT u.uid, u.username, 
  CASE WHEN p.uid IS NULL
  THEN NULL 
  ELSE CONCAT('[', 
    GROUP_CONCAT(CONCAT(' "pid":',p.pid,',"title":"', REPLACE(p.title, '"', '\\"'),
           '","status":',p.status, ' ')), ']') END portfolios
FROM user u 
LEFT JOIN portfolio p 
  ON u.uid=p.uid AND p.status=1
GROUP BY u.uid, u.username;

...这会给你...

+------+----------+------------------------------------------------------------------------------------------------------------------------------+
| uid  | username | portfolios                                                                                                                   |
+------+----------+------------------------------------------------------------------------------------------------------------------------------+
|    1 | manoj    | [ "pid":2,"title":"title 2","status":1 , "pid":3,"title":"title 3","status":1 , "pid":1,"title":"title 1","status":1 ] |
|    2 | testing  | [ "pid":4,"title":"title 1","status":1 ]                                                                                   |
|    3 | user     | NULL                                                                                                                         |
|    4 | company  | NULL                                                                                                                         |
+------+----------+------------------------------------------------------------------------------------------------------------------------------+

【讨论】:

向我显示此错误“您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以获取在 'JSON) 附近使用的正确语法”并且我还想选择投资组合只有状态 = 1 @ManojKumar 您正在运行哪个 MySQL 版本?只有 5.7.8 及更高版本原生支持 JSON。 Okey.. 我正在使用“5.6.28-0ubuntu0.15.04.1” @ManojKumar 使用不使用内置 JSON 支持的字符串构建版本更新了答案。 我们还可以在用户的​​foreach循环中获取投资组合。这是获得的好习惯。在 foreach 中获取投资组合或使用您已解释的单个查询。 @Joachim Lsaksson【参考方案2】:

MySQL 8:带有JSON_OBJECTAGGJSON_OBJECT 函数

SELECT 
    u.user_id,
    u.username,
    CASE WHEN p.user_id IS NULL
        THEN NULL 
    ELSE 
        JSON_OBJECTAGG(
            IF(p.portfolio_id IS NULL, '', p.portfolio_id ), 
            JSON_OBJECT('title', p.title, 'status', p.status)) END portfolios
FROM user AS u
LEFT JOIN portfolio AS p ON u.user_id = p.user_id AND p.status = 1
GROUP BY u.user_id;

结果:

+---------+----------+--------------------------------------------------------------------------------------------------------------------------+
| user_id | username | portfolios                                                                                                               |
+---------+----------+--------------------------------------------------------------------------------------------------------------------------+
|       1 | manoj    | "1": "title": "title 1", "status": 1, "2": "title": "title 2", "status": 1, "3": "title": "title 3", "status": 1 |
|       2 | testing  | "4": "title": "title 1", "status": 1                                                                                 |
|       3 | user     | NULL                                                                                                                     |
|       4 | company  | NULL                                                                                                                     |
+---------+----------+--------------------------------------------------------------------------------------------------------------------------+

【讨论】:

【参考方案3】:

从 5.7 开始使用

JSON_OBJECT('key1', 1, 'key2', 'abc');

它比多个 concat 语句更简单,并且具有相同的效果。

【讨论】:

【参考方案4】:

使用group_concat

select UID,USERNAME,concat('JSON OBJECT OF PID (',group_concat(PID),')') PORTFOLIO 
from User u join Portfolio p
on u.UID=p.UID group by UID 

或者试试这个:-

SELECT u.UID,NAME,concat('JSON OBJECT OF PID (',group_concat(pid),')') 
FROM `User` u LEFT join Portfolio p
on u.UID=p.UID group by u.UID

【讨论】:

这不会返回 JSON 数据,它只是在 PORTFOLIO 列中的投资组合表中添加逗号分隔的列值,而且我想对状态 = 1 的投资组合的选择设置条件 你需要什么?你能显示一些样本数据吗@ManojKumar 我在 phpmyadmin @rahautos 的问题中添加了截图

以上是关于如果子查询在 MySQL 中返回多于 1 行,如何将 JSON 放入列数据中的主要内容,如果未能解决你的问题,请参考以下文章

SQL 在 select 子查询中只返回一行或 null

(My)SQL:如果子查询不是空集,则返回子查询

Group BY 子查询返回多于 1 行

如果子查询没有返回结果,为啥“= ALL(子查询)”评估为真?

如果子查询的结果为 NULL,MySQL 整个查询将失败

ORA-01427单行子查询返回多于 1 行