peewee 的多个聚合函数
Multiple aggregate functions with peewee
我几乎不知道 SQL 但我一直在使用 peewee
并且到目前为止效果非常好。我遇到了一个我不确定如何解决的问题。这是设置。
我有两个表 A
和 B
。 A
在其他字段中有多个带有外键的 B
。 B
有 3 个字段(在我的例子中是 5 个,但 3 个是要重现的最小值):
A:
id param_1 ...
0 ...
1 ...
2 ...
和
B:
id A_key x y z
0 0 3. 5. 1
1 0 4. 4. 2
2 1 2. 3. 3
3 1 5. 1. 4
我想得到 z
一方面对应 x
的最小值,另一方面 y
,对于每个 A
.
x
或 y
这样做很容易:(Q1)
A.select(fn.MIN(B.x), B.z.alias('z_x')).join(B).group_by(A)
> A_id x z_x
> 0 3. 1
> 1 2. 3
我也可以为 B 做同样的事情。我的问题是:你会怎么做才能同时拥有两者? (Q2)
???
> A_id x z_x y z_y
> 0 3. 1 4. 2
> 1 2. 3 1. 4
当然,我试过了
A.select(fn.MIN(B.x), B.z.alias('z_x'), fn.MIN(B.y), B.z.alias('z_y')).join(B).group_by(A)
但是 z_x
列刚刚被 z_y
替换。
对于那里的 SQL 专家,(Q1) 对应于
SELECT MIN("t1"."x"), "t1"."z" FROM "A" AS "t2" INNER JOIN "B" AS "t1" ON ("t1"."A_id" = "t2"."id") GROUP BY "t2"."id"
如果有人看到纯 SQL!
中的解决方案,我还可以在 peewee 中翻译 SQL 查询 (Q2)
很高兴得到任何帮助,如果需要,我可以提供更多详细信息!
这最终比我最初想象的要难,因为 Sqlite 有点让查询的简化版本工作......但是它们 相当 正确。无论如何,至少就我理解的问题而言,以下似乎工作正常(为每个 A 获取最小 X 和最小 Y 的 Z):
class A(Base):
key = TextField()
class B(Base):
a = ForeignKeyField(A)
x = IntegerField()
y = IntegerField()
z = IntegerField()
db.create_tables([A, B])
a1 = A.create(key='a1')
a2 = A.create(key='a2')
B.create(a=a1, x=1, y=100, z=10)
B.create(a=a1, x=10, y=10, z=5)
B.create(a=a1, x=100, y=1, z=2)
B.create(a=a2, x=2, y=200, z=20)
B.create(a=a2, x=20, y=20, z=15)
B.create(a=a2, x=200, y=4, z=10)
# The idea is we will create first a query that gets us
# the minimum X for each A (subq).
BX = B.alias()
subq = BX.select(BX.a, fn.MIN(BX.x).alias('minx')).group_by(BX.a)
# Then we want to get the Z's for all rows whose X is
# equal to the minimum X (for each A).
z_for_x = (BX
.select(BX.a, BX.z, subq.c.minx)
.join(subq, on=((BX.a == subq.c.a_id) & (BX.x == subq.c.minx)))
.group_by(BX.a, BX.z))
# Do the same for the Y's.
# First find the minimum Y for each A.
BY = B.alias()
subq = BY.select(BY.a, fn.MIN(BY.y).alias('miny')).group_by(BY.a)
# Then get all Z's for each A whose Y is equal to the
# minimum Y we found.
z_for_y = (BY
.select(BY.a, BY.z, subq.c.miny)
.join(subq, on=((BY.a == subq.c.a_id) & (BY.y == subq.c.miny)))
.group_by(BY.a, BY.z))
# We'll use common table expressions to access these
# two distinct subqueries.
xcte = z_for_x.cte('zforx', columns=['ba', 'bz', 'minx'])
ycte = z_for_y.cte('zfory', columns=['ba', 'bz', 'miny'])
# Then get all A's and their associated minimum X and it's
# corresponding Z, and minimum Y and it's corresponding Z:
q = (A.select(A, xcte.c.minx, xcte.c.bz, ycte.c.miny, ycte.c.bz)
.join_from(A, xcte, JOIN.INNER, on=(A.id == xcte.c.ba))
.join_from(A, ycte, JOIN.INNER, on=(A.id == ycte.c.ba))
.with_cte(xcte, ycte))
# Execute our query:
for row in q.tuples():
print(row)
#OUTPUT:
# 1, 'a1', 1, 10, 1, 2
# 2, 'a2', 2, 20, 4, 10
输出说明:
对于 a1,最小 X=1(z=10),最小 Y=1(z=2)
对于 a2,最小 X=2(z=20),最小 Y=4(z=10)
我几乎不知道 SQL 但我一直在使用 peewee
并且到目前为止效果非常好。我遇到了一个我不确定如何解决的问题。这是设置。
我有两个表 A
和 B
。 A
在其他字段中有多个带有外键的 B
。 B
有 3 个字段(在我的例子中是 5 个,但 3 个是要重现的最小值):
A:
id param_1 ...
0 ...
1 ...
2 ...
和
B:
id A_key x y z
0 0 3. 5. 1
1 0 4. 4. 2
2 1 2. 3. 3
3 1 5. 1. 4
我想得到 z
一方面对应 x
的最小值,另一方面 y
,对于每个 A
.
x
或 y
这样做很容易:(Q1)
A.select(fn.MIN(B.x), B.z.alias('z_x')).join(B).group_by(A)
> A_id x z_x
> 0 3. 1
> 1 2. 3
我也可以为 B 做同样的事情。我的问题是:你会怎么做才能同时拥有两者? (Q2)
???
> A_id x z_x y z_y
> 0 3. 1 4. 2
> 1 2. 3 1. 4
当然,我试过了
A.select(fn.MIN(B.x), B.z.alias('z_x'), fn.MIN(B.y), B.z.alias('z_y')).join(B).group_by(A)
但是 z_x
列刚刚被 z_y
替换。
对于那里的 SQL 专家,(Q1) 对应于
SELECT MIN("t1"."x"), "t1"."z" FROM "A" AS "t2" INNER JOIN "B" AS "t1" ON ("t1"."A_id" = "t2"."id") GROUP BY "t2"."id"
如果有人看到纯 SQL!
中的解决方案,我还可以在 peewee 中翻译 SQL 查询 (Q2)很高兴得到任何帮助,如果需要,我可以提供更多详细信息!
这最终比我最初想象的要难,因为 Sqlite 有点让查询的简化版本工作......但是它们 相当 正确。无论如何,至少就我理解的问题而言,以下似乎工作正常(为每个 A 获取最小 X 和最小 Y 的 Z):
class A(Base):
key = TextField()
class B(Base):
a = ForeignKeyField(A)
x = IntegerField()
y = IntegerField()
z = IntegerField()
db.create_tables([A, B])
a1 = A.create(key='a1')
a2 = A.create(key='a2')
B.create(a=a1, x=1, y=100, z=10)
B.create(a=a1, x=10, y=10, z=5)
B.create(a=a1, x=100, y=1, z=2)
B.create(a=a2, x=2, y=200, z=20)
B.create(a=a2, x=20, y=20, z=15)
B.create(a=a2, x=200, y=4, z=10)
# The idea is we will create first a query that gets us
# the minimum X for each A (subq).
BX = B.alias()
subq = BX.select(BX.a, fn.MIN(BX.x).alias('minx')).group_by(BX.a)
# Then we want to get the Z's for all rows whose X is
# equal to the minimum X (for each A).
z_for_x = (BX
.select(BX.a, BX.z, subq.c.minx)
.join(subq, on=((BX.a == subq.c.a_id) & (BX.x == subq.c.minx)))
.group_by(BX.a, BX.z))
# Do the same for the Y's.
# First find the minimum Y for each A.
BY = B.alias()
subq = BY.select(BY.a, fn.MIN(BY.y).alias('miny')).group_by(BY.a)
# Then get all Z's for each A whose Y is equal to the
# minimum Y we found.
z_for_y = (BY
.select(BY.a, BY.z, subq.c.miny)
.join(subq, on=((BY.a == subq.c.a_id) & (BY.y == subq.c.miny)))
.group_by(BY.a, BY.z))
# We'll use common table expressions to access these
# two distinct subqueries.
xcte = z_for_x.cte('zforx', columns=['ba', 'bz', 'minx'])
ycte = z_for_y.cte('zfory', columns=['ba', 'bz', 'miny'])
# Then get all A's and their associated minimum X and it's
# corresponding Z, and minimum Y and it's corresponding Z:
q = (A.select(A, xcte.c.minx, xcte.c.bz, ycte.c.miny, ycte.c.bz)
.join_from(A, xcte, JOIN.INNER, on=(A.id == xcte.c.ba))
.join_from(A, ycte, JOIN.INNER, on=(A.id == ycte.c.ba))
.with_cte(xcte, ycte))
# Execute our query:
for row in q.tuples():
print(row)
#OUTPUT:
# 1, 'a1', 1, 10, 1, 2
# 2, 'a2', 2, 20, 4, 10
输出说明:
对于 a1,最小 X=1(z=10),最小 Y=1(z=2)
对于 a2,最小 X=2(z=20),最小 Y=4(z=10)