如果子查询在 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_OBJECTAGG
和JSON_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 放入列数据中的主要内容,如果未能解决你的问题,请参考以下文章