如何在 Gorm 中留下连接子查询计数

Posted

技术标签:

【中文标题】如何在 Gorm 中留下连接子查询计数【英文标题】:How to left join subquery count in Gorm 【发布时间】:2021-12-19 21:03:32 【问题描述】:

我希望我的 Gorm 查询返回正确的 version_count。我的 Gorm 查询返回 0 version_count,而我的 mysql 查询返回 version_count。

我有下面的 MySQL 查询,用于将子查询计数连接到最终查询结果中。

我有这个用于我的 Gorm 查询:

subQuery := models.DB.Select("services.id as services_id, COUNT(versions.service_id) as version_count").Group("services.id").Preload("Versions").Table("Services").SubQuery()
models.DB.Preload("Versions").Find(&services).Count(&count).Limit(limit).Offset(offset).
    Joins("LEFT JOIN (?) as version_counts ON version_counts.services_id = s.id", subQuery)

去结构

type Service struct 
    ID          uint        `json:"id" gorm:"primary_key"`
    Name        string      `json:"name"`
    Description string      `json:"description"`
    Versions    []Version   `json:"versions"`
    VersionCount int        `json:"version_count"`
    CreatedAt   string      `json:"created_at"`


type Version struct 
    ID           uint   `json:"id" gorm:"primary_key"`
    Version      string `json:"name"`
    ServiceID    string `json:"service_id"`
    CreatedAt    string `json:"created_at"`
    UpdatedAt    string `json:"updated_at"`

有我的查询表。

mysql> select * from services;
+----+---------------------+---------------------+------------+--------+-------------+
| id | created_at          | updated_at          | deleted_at | name   | description |
+----+---------------------+---------------------+------------+--------+-------------+
|  1 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       | John   | New York    |
|  2 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       | Martin | Los Angeles |
+----+---------------------+---------------------+------------+--------+-------------+
2 rows in set (0.02 sec)

mysql> select * from versions;
+----+---------------------+---------------------+------------+------------+---------+
| id | created_at          | updated_at          | deleted_at | service_id | version |
+----+---------------------+---------------------+------------+------------+---------+
|  1 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       |          1 | 1.0.0   |
|  2 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       |          1 | 1.0.1   |
|  3 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       |          1 | 1.0.2   |
|  4 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       |          2 | 1.0.0   |
|  5 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       |          2 | 1.0.1   |
|  6 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       |          2 | 1.0.2   |
|  7 | 2021-11-05 21:16:25 | 2021-11-05 21:16:25 | NULL       |          2 | 1.0.3   |
+----+---------------------+---------------------+------------+------------+---------+
7 rows in set (0.01 sec)

mysql> select * from services s join versions v on v.service_id = s.id left join ( select s.id services_id, count(v.service_id) as version_count from services s join versions v on v.service_id = s.id group by s.id) version_counts ON version_counts.services_id = s.id;
+----+---------------------+---------------------+------------+--------+-------------+----+---------------------+---------------------+------------+------------+---------+-------------+---------------+
| id | created_at          | updated_at          | deleted_at | name   | description | id | created_at          | updated_at          | deleted_at | service_id | version | services_id | version_count |
+----+---------------------+---------------------+------------+--------+-------------+----+---------------------+---------------------+------------+------------+---------+-------------+---------------+
|  1 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       | John   | New York    |  1 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       |          1 | 1.0.0   |           1 |             3 |
|  1 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       | John   | New York    |  2 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       |          1 | 1.0.1   |           1 |             3 |
|  1 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       | John   | New York    |  3 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       |          1 | 1.0.2   |           1 |             3 |
|  2 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       | Martin | Los Angeles |  4 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       |          2 | 1.0.0   |           2 |             4 |
|  2 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       | Martin | Los Angeles |  5 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       |          2 | 1.0.1   |           2 |             4 |
|  2 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       | Martin | Los Angeles |  6 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       |          2 | 1.0.2   |           2 |             4 |
|  2 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       | Martin | Los Angeles |  7 | 2021-11-05 20:20:09 | 2021-11-05 20:20:09 | NULL       |          2 | 1.0.3   |           2 |             4 |
+----+---------------------+---------------------+------------+--------+-------------+----+---------------------+---------------------+------------+------------+---------+-------------+---------------+
7 rows in set (0.01 sec)

【问题讨论】:

【参考方案1】:

我能够使用适当的 version_count 加载响应。

带有原始查询的 Gorm(更短更容易)

models.DB.Preload("Versions").Table("Services s").
    Select("*").
    Joins("left join (select s.id services_id, count(v.service_id) as version_count " +
        "from services s " +
        "join versions v on v.service_id = s.id " +
        "group by s.id) version_counts " +
        "ON version_counts.services_id = s.id").
    Find(&services)

Gorm 查询(更复杂)

subQuery := models.DB.Debug().Table("Services s").
    Select("s.id services_id, count(v.service_id) as version_count").
    Joins("JOIN versions v ON v.service_id = s.id").Group("s.id").SubQuery()

models.DB.Debug().Preload("Versions").Table("Services s").
    Select("*").
    Joins("left join " +
        "(" +
            "?" +
        ") version_counts " +
        "ON version_counts.services_id = s.id", subQuery).
    Find(&services).Count(&count).Limit(limit).Offset(offset)

【讨论】:

以上是关于如何在 Gorm 中留下连接子查询计数的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有算术计数的SQL子查询中使用GROUP BY

Mysql添加连接子查询以计数

如何提高 SQL Server 查询的性能以选择具有值的行不在子查询中的一次计数

命名查询中的 Grails GORM 计数函数

Sql子查询比较两个计数

MSSQL之五 连接查询与子查询