【问题标题】:Peewee group_concat/case issuePeewee group_concat/案例问题
【发布时间】:2019-01-23 08:48:44
【问题描述】:

我正在尝试使用 peewee 从使用 GROUP_CONCAT 和 Case 的 sqlite 数据库中获取和格式化一些数据。但我在使用这些功能时遇到了问题。


首先让我们从我想要实现的目标开始:

我简化了我的表结构以更好地指出问题:1 个包含两列的简单表:name (Char)、is_controlled (Boolean)。 此 SQL 请求计算所需的结果:

SELECT 
    SUM(is_controlled),
    GROUP_CONCAT(CASE WHEN is_controlled = 1 THEN name ELSE NULL END, ':') as controlled,
    GROUP_CONCAT(CASE WHEN is_controlled = 0 THEN name ELSE NULL END, ':') as not_controlled
FROM component;

输出(这是我对 peewee 的期望):

2
comp1:comp3
comp2

这是一个可以测试我的问题的脚本:

from peewee import *

db = SqliteDatabase('test.db')


class Component(Model):
name = CharField()
is_controlled = BooleanField()

class Meta:
database = db


raw_data = [
    {'name': 'comp1', 'is_controlled': True},
    {'name': 'comp2', 'is_controlled': False},
    {'name': 'comp3', 'is_controlled': True},
]

db.connect()

# Populate database
db.create_tables([Component])
for item in raw_data:
    Component.get_or_create(**item)

res = Component.select(
    fn.Sum(Component.is_controlled).alias('controlled_count'),
    fn.GROUP_CONCAT(Case(None, [((Component.is_controlled == True), Component.name)], None), ':').alias('controlled'),
    fn.GROUP_CONCAT(Case(None, [((Component.is_controlled == False), Component.name)], None), ':').alias('not_controlled')
)


print res[0].controlled_count
print res[0].controlled
print res[0].not_controlled

db.close()

如您所见,数据结构很简单(我在最大程度上简化了示例)。输出是:

2
:comp3:
:

我检查了 peewee 生成的 SQL 查询(使用 res.sql()),它看起来像这样:

sql = 'SELECT Sum("t1"."is_controlled") AS "controlled_count", GROUP_CONCAT(CASE WHEN ("t1"."is_controlled" = ?) THEN ? END, "t1"."name") AS "controlled", GROUP_CONCAT(CASE WHEN ("t1"."is_controlled" = ?) THEN ? END, "t1"."name") AS "not_controlled" FROM "component" AS "t1"'

params = [True, ':', False, ':']

我们可以看到 peewee 生成的 SQL 请求中缺少 ELSE NULL 部分。我尝试了几件事,比如调整给 Case 函数的参数,但我无法让它正常工作。

如何正确使用 peewee 得到与使用 SQL 相同的结果?

(我使用 python 2.7.15 和 peewee 3.6.4 和 sqlite 3.19.4)

【问题讨论】:

    标签: python peewee


    【解决方案1】:

    Case 函数的签名提供了一个线索:

    def Case(predicate, expression_tuples, default=None):
    

    在代码内部,它检查:

    if default is not None:
        clauses.extend((SQL('ELSE'), default))
    

    因此,当您传递 None 时,它与“空/未指定”的情况无法区分,Peewee 会忽略它。

    作为一种解决方法,您可以指定 SQL('NULL') 作为默认值。或者你可以使用一个空字符串,虽然我不确定你是否依赖于带有空值的 group-concat 的某些行为,所以这可能不起作用?

    【讨论】:

    • 非常感谢您的快速响应(也感谢大家的 peewee!)。这是有效的,我在我的例子中犯了一个错误(我反转了一些参数),这是我想要的:fn.GROUP_CONCAT(Case(None, [((Component.is_controlled == True), Component.name)], SQL('NULL')), ':')
    猜你喜欢
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 2016-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多