在包含多个相关项的 sql 查询中返回 json

Posted

技术标签:

【中文标题】在包含多个相关项的 sql 查询中返回 json【英文标题】:Return json in a sql query which is multiple related items 【发布时间】:2018-11-18 18:59:08 【问题描述】:

我有一个 web 应用程序,它显示项目列表。

每个项目可以有一个或多个标签。

项目(ID,名称)

标签(ID,名称)

ItemTag(Id, ItemId, TagId)

如果只显示单个项目,则很容易获取项目,然后是标签并在 UI 中显示它们。

但是,当显示可能显示 100 个项目的项目网格时,我想避免必须执行 101 次访问数据库 - 一次获取项目列表,然后为每个集合往返一次数据库每个项目的标签。

我能想到的最好的方法是进行基本查询,然后使用结果构建第二个查询,使用 Id 返回一个长标签列表,然后我将其匹配到各个项目。

有没有更好的方法来做到这一点?例如,如果标签列表可以转换为 json 并在原始查询中作为字符串返回,那么在客户端我可以将其转换回对象并适当地显示它们。但是我不知道怎么写这样的查询。

【问题讨论】:

【参考方案1】:

注意:此问题最初标记为 SQL Server 2012。

您正在寻找字符串聚合——或类似的东西。在 SQL Server 2012+ 中,最好的方法可能是这个 XML 方法,它以逗号分隔的字符串返回标签:

SELECT i.*,
       STUFF( (SELECT ',' + t.name
               FROM tags t JOIN
                    ItemTags it
                    ON it.TagID = t.ID
               WHERE i.ID = it.ItemID
               ORDER BY t.name
               FOR XML PATH ('')
              ), 1, 1, ''
            ) as tags
WHERE i.Created >= '2018-01-01' and
      i.Created < '2018-02-01';

【讨论】:

【参考方案2】:

然后可以在标签上使用您为选择项目提出的任何逻辑:

--suppose this returns 100 items
SELECT * FROM Items WHERE Created BETWEEN '2018-01-01' and '2018-02-01'

--select th tags from the items
SELECT t.* 
FROM Items i 
INNER JOIN ItemTags it ON i.ID = it.ItemID
INNER JOIN Tags t ON it.TagID = t.ID
WHERE i.Created BETWEEN '2018-01-01' and '2018-02-01'

相同的谓词选择相同的100个项目,数据库通过ItemTags连接到Tags,并返回所有的标签数据。如果你想知道哪个标签数据和哪个项目一起,记得选择它

【讨论】:

【参考方案3】:

使用 Sql Server 2016+,您可以使用 FOR JSON AUTO 返回 json。

SELECT i.Name,
(Select t.Name From ItemTags it join Tags t on it.TagId = t.Id Where it.ItemId = i.Id for json auto) as Tags
        from Items i
        where i.Id = 2390

结果:

【讨论】:

问题标记为 sql-server-2012 ? @CaiusJard,我本来以为我用的是2012,结果我弄错了。我已经更新了问题。

以上是关于在包含多个相关项的 sql 查询中返回 json的主要内容,如果未能解决你的问题,请参考以下文章

SQL JOIN 查询返回我们在连接表中没有找到匹配项的行

如何编写从两个搜索值返回匹配项的 sql 查询

ThinkPHP中查询数据库where()中的条件必须包含主键值吗

如何使用 PHP 处理从 SQL 查询返回的树结构?

ES搜索结果中各个字段介绍

具有多个包含的Linq-to-Sql