【问题标题】:Why does django queryset.extra() throws OperationalError: (1242, 'Subquery returns more than 1 row')?为什么 django queryset.extra() 会抛出 OperationalError: (1242, 'Subquery returns more than 1 row')?
【发布时间】:2019-09-09 08:33:13
【问题描述】:

我将 Django ORMMySQL 一起使用,并在查询上浪费了大量时间。对于一些“高级”案例,我决定使用原始查询,因为对于那些,我无法使用注释。原始查询的问题是不要像注释或聚合一样向查询集添加“字段”。所以,我正在使用 额外。但现在我面临一个问题

qs_products = Productos.objects.all()
qs_productos.extra({
    "stock":
    """
        SELECT SUM(items.cantidad)
        FROM 
            `encargosProveedor_listado_articulos` AS encargos, 
            `itemArticulosProveedor`AS items, `articulos` as articulos
        WHERE 
            encargos.itemarticulosproveedor_id=items.id and 
            articulos.id=items.articulos_id
        GROUP BY articulos.producto_id
    """
    })

这是直接来自我的数据库管理员的此查询的结果

+---------------------+
| SUM(items.cantidad) |
+---------------------+
|          14         |
+---------------------+
|          4          |
+---------------------+

但是当使用 extra()

在 django 下运行这段代码时

MySQLdb._exceptions.OperationalError: (1242, '子查询返回超过 1 行')

返回多行有什么问题?查询返回两行,因为我有两个产品,这是合理的。我想将 stock 分配给每个产品。

替代方案?建议?提示?

【问题讨论】:

    标签: python mysql django django-models


    【解决方案1】:

    您正在尝试在外部查询和extra 子查询之间进行连接,而数据库需要显式连接子句来执行此操作。我相信您可以在 extra 中添加 WHERE 子句以使其正常工作:

    qs_productos.extra({
        "stock":
        """
            SELECT SUM(items.cantidad)
            FROM 
                `encargosProveedor_listado_articulos` AS encargos, 
                `itemArticulosProveedor`AS items, `articulos` as articulos
            WHERE 
                articulos.producto_id = productos.id and
                encargos.itemarticulosproveedor_id=items.id and 
                articulos.id=items.articulos_id       
            GROUP BY articulos.producto_id
        """
    })
    

    articulos.producto_id = productos.id 中的productos 需要替换为主查询中的实际表名。

    由于 extra 已被弃用(从 Django 2.2 开始还没有完全弃用),因此这里是等效的 RawSQL 查询:

    qs_productos.annotate(stock=RawSQL(
        """
            SELECT SUM(items.cantidad)
            FROM 
                `encargosProveedor_listado_articulos` AS encargos, 
                `itemArticulosProveedor`AS items, `articulos` as articulos
            WHERE 
                articulos.producto_id = productos.id and
                encargos.itemarticulosproveedor_id=items.id and 
                articulos.id=items.articulos_id       
            GROUP BY articulos.producto_id
        """,
        ()
    ))
    

    RawSQL 中的空元组是必需的,因为该函数采用 params 元组参数,即使您没有要传递的参数,该参数也不是可选的。

    作为奖励,RawSQL 对先前的values 调用不太敏感,并在需要时提供可选的output_field 参数。

    【讨论】:

    • 谢谢!有效。但是,我仍然没有在我的查询集中获得“股票”字段。你知道为什么吗?
    • 我能想到的唯一原因是在extra()之前使用values(),在这种情况下extra字段是silently discarded
    • 不,我在查询后使用 values() 来显示/查看是否有股票字段。
    • 那么您需要调试潜伏在代码中某处的错误。或者您可以尝试上面提供的RawSQL 替代方案,也许它可以解决问题。
    猜你喜欢
    • 1970-01-01
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-02
    • 2018-06-28
    • 1970-01-01
    • 2016-03-03
    相关资源
    最近更新 更多