获取多对多的 ID table
Get ids of many to many table
在 django 中,如果 table 有这样的多对多字段:
class Category(models.Model):
name = models.CharField(unique=True, max_length=255)
icon = models.ImageField(upload_to='images')
sport = models.ManyToManyField(Sport)
当您尝试从此 table 获取所有对象时,您可以这样做:
Category.objects.all()
序列化后的结果是这样的:
"data": [
{
"id": 1,
"name": '..'
"icon": '...'
"sport": [
1,
2
]
]
}
所以我的问题是如何使用纯 sql 获得相同的结果
我试过了:
sql = '''select a.*,b.sport_id,array_agg(b.sport_id) as sport from category a join category_sport b on b.category_id=a.id group by a.id,b.sport_id ;'''
但结果是这样的:
"data": [
{
"id": 1,
"name": '..'
"icon": '...'
"sport": [
1,
]
},
{
"id": 1,
"name": '..'
"icon": '...'
"sport": [
2
]
]
}
根据我的理解,如果你需要实现你只需要删除 b.sport_id
,你想将 sport_id
连接到每个类别的数组中,所以没有理由按此分组字段,您的 SQL 应该是:
sql = '''select a.id, array_agg(b.sport_id) as sport from category a join category_sport b on b.category_id=a.id group by a.id;'''
请记住,所有非聚合的选定字段都应按部分显示在组中。
另一种选择,如果您使用的是 PostgreSQL,可以使用 ArrayAgg
,例如:
from django.contrib.postgres.aggregates import ArrayAgg
Category.objects.aggregate(sport=ArrayAgg('sport__id'))
此外,您还可以看到这个非常简单的 PostgreSQL13 示例:
架构:
CREATE TABLE a (
id INT,
title VARCHAR(128)
);
CREATE TABLE b (
id INT
);
CREATE TABLE ab (
id INT,
aid INT,
bid INT
);
INSERT INTO a (id, title) VALUES (1, 'title_a');
INSERT INTO a (id, title) VALUES (2, 'title_b');
INSERT INTO b (id) VALUES (1);
INSERT INTO b (id) VALUES (2);
INSERT INTO b (id) VALUES (3);
INSERT INTO b (id) VALUES (4);
INSERT INTO b (id) VALUES (5);
INSERT INTO b (id) VALUES (6);
INSERT INTO ab (id, aid, bid) VALUES(1, 1, 1);
INSERT INTO ab (id, aid, bid) VALUES(2, 1, 3);
INSERT INTO ab (id, aid, bid) VALUES(3, 1, 5);
INSERT INTO ab (id, aid, bid) VALUES(4, 2, 2);
INSERT INTO ab (id, aid, bid) VALUES(5, 2, 4);
INSERT INTO ab (id, aid, bid) VALUES(6, 2, 6);
查询:
SELECT a.id, a.title, array_agg(ab.bid) AS bs FROM a JOIN ab ON a.id=ab.aid GROUP BY a.id, a.title;
结果:
| id | title | bs |
| --- | ------- | ------- |
| 2 | title_b | [2,4,6] |
| 1 | title_a | [1,3,5] |
上进行测试
在 django 中,如果 table 有这样的多对多字段:
class Category(models.Model):
name = models.CharField(unique=True, max_length=255)
icon = models.ImageField(upload_to='images')
sport = models.ManyToManyField(Sport)
当您尝试从此 table 获取所有对象时,您可以这样做:
Category.objects.all()
序列化后的结果是这样的:
"data": [
{
"id": 1,
"name": '..'
"icon": '...'
"sport": [
1,
2
]
]
}
所以我的问题是如何使用纯 sql 获得相同的结果 我试过了:
sql = '''select a.*,b.sport_id,array_agg(b.sport_id) as sport from category a join category_sport b on b.category_id=a.id group by a.id,b.sport_id ;'''
但结果是这样的:
"data": [
{
"id": 1,
"name": '..'
"icon": '...'
"sport": [
1,
]
},
{
"id": 1,
"name": '..'
"icon": '...'
"sport": [
2
]
]
}
根据我的理解,如果你需要实现你只需要删除 b.sport_id
,你想将 sport_id
连接到每个类别的数组中,所以没有理由按此分组字段,您的 SQL 应该是:
sql = '''select a.id, array_agg(b.sport_id) as sport from category a join category_sport b on b.category_id=a.id group by a.id;'''
请记住,所有非聚合的选定字段都应按部分显示在组中。
另一种选择,如果您使用的是 PostgreSQL,可以使用 ArrayAgg
,例如:
from django.contrib.postgres.aggregates import ArrayAgg
Category.objects.aggregate(sport=ArrayAgg('sport__id'))
此外,您还可以看到这个非常简单的 PostgreSQL13 示例:
架构:
CREATE TABLE a (
id INT,
title VARCHAR(128)
);
CREATE TABLE b (
id INT
);
CREATE TABLE ab (
id INT,
aid INT,
bid INT
);
INSERT INTO a (id, title) VALUES (1, 'title_a');
INSERT INTO a (id, title) VALUES (2, 'title_b');
INSERT INTO b (id) VALUES (1);
INSERT INTO b (id) VALUES (2);
INSERT INTO b (id) VALUES (3);
INSERT INTO b (id) VALUES (4);
INSERT INTO b (id) VALUES (5);
INSERT INTO b (id) VALUES (6);
INSERT INTO ab (id, aid, bid) VALUES(1, 1, 1);
INSERT INTO ab (id, aid, bid) VALUES(2, 1, 3);
INSERT INTO ab (id, aid, bid) VALUES(3, 1, 5);
INSERT INTO ab (id, aid, bid) VALUES(4, 2, 2);
INSERT INTO ab (id, aid, bid) VALUES(5, 2, 4);
INSERT INTO ab (id, aid, bid) VALUES(6, 2, 6);
查询:
SELECT a.id, a.title, array_agg(ab.bid) AS bs FROM a JOIN ab ON a.id=ab.aid GROUP BY a.id, a.title;
结果:
| id | title | bs |
| --- | ------- | ------- |
| 2 | title_b | [2,4,6] |
| 1 | title_a | [1,3,5] |
上进行测试