<column_name> 不包含在聚合函数或 GROUP BY 子句中。 (8120)

问题描述 投票:0回答:1

我有一个 Flask 应用程序,其数据库后端是 MS SQL Server。我正在尝试编写一个查询。

    active_with_schools = db.query(
        Registration.id,
        Registration.uuid,
        Registration.last_name,
        Registration.first_name,
        Registration.email,
        Registration.phone,
        Registration.date_added,
        Registration.other_heard_from,
        Registration.other_feedback,
        func.coalesce(
            Registration.date_expired,
            datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S')
        ),
        func.coalesce(
            Registration.expired_by, ''
        ),
        func.count(School.registration_id)
    ).join(
        User,
        User.email == Registration.email
    ).join(
        School,
        School.registration_id == Registration.id,
        isouter=True
    ).filter(
        func.coalesce(
            Registration.date_expired,
            datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S')
        ) < datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S')
    ).group_by(
        Registration.id,
        Registration.uuid,
        Registration.last_name,
        Registration.first_name,
        Registration.email,
        Registration.phone,
        Registration.date_added,
        Registration.other_heard_from,
        Registration.other_feedback,
        func.coalesce(
            Registration.date_expired,
            datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S')
        ),
        func.coalesce(
            Registration.expired_by, ''
        )
    ).having(
        func.count(
            func.coalesce(
                School.registration_id, -1
            )
        ) > 0
    ).order_by(
        Registration.date_added.desc()
    ).all()

这会引发“ProgrammingError”异常(稍作编辑):

(pyodbc.ProgrammingError) ('42000', "[42000] [Microsoft][ODBC Driver 
18 for SQL Server][SQL Server]Column 'MySchema.registration.date_expired'
is invalid in the select list because it is not contained in either an 
aggregate function or the GROUP BY clause. (8120) (SQLExecDirectW); 
[42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Column
'MySchema.registration.date_expired' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY clause.
(8120); [42000] [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]
Statement(s) could not be prepared. (8180)")
[SQL: SELECT [MySchema].registration.id AS [MySchema_registration_id],
            [MySchema].registration.uuid AS [MySchema_registration_uuid],
            [MySchema].registration.last_name AS [MySchema_registration_last_name], 
            [MySchema].registration.first_name AS [MySchema_registration_first_name], 
            [MySchema].registration.email AS [MySchema_registration_email],
            [MySchema].registration.phone AS [MySchema_registration_phone],
            [MySchema].registration.date_added AS [MySchema_registration_date_added], 
            [MySchema].registration.other_heard_from AS [MySchema_registration_other_heard_from], 
            [MySchema].registration.other_feedback AS [MySchema_registration_other_feedback], 
            coalesce([MySchema].registration.date_expired, ?) AS coalesce_1,
            coalesce([MySchema].registration.expired_by, ?) AS coalesce_3,
            count([MySchema].school.registration_id) AS count_1 
FROM [MySchema].registration 
    JOIN [MySchema].[user] 
        ON [MySchema].[user].email = [MySchema].registration.email 
    LEFT OUTER JOIN [MySchema].school 
        ON [MySchema].school.registration_id = [MySchema].registration.id 
WHERE coalesce([MySchema].registration.date_expired, ?) < ? 
GROUP BY [MySchema].registration.id, 
    [MySchema].registration.uuid, 
    [MySchema].registration.last_name, 
    [MySchema].registration.first_name, 
    [MySchema].registration.email, 
    [MySchema].registration.phone, 
    [MySchema].registration.date_added, 
    [MySchema].registration.other_heard_from, 
    [MySchema].registration.other_feedback, 
    coalesce([MySchema].registration.date_expired, ?),
    coalesce([MySchema].registration.expired_by, ?) 
HAVING count(coalesce([MySchema].school.registration_id, ?)) > ? 
ORDER BY [MySchema].registration.date_added DESC]
[parameters: (
    '2024-05-16 16:36:39', 
    '', 
    '2024-05-16 16:36:39', 
    '2024-05-16 16:36:39', 
    '2024-05-16 16:36:39', 
    '', 
    -1, 
    0
)]
(Background on this error at: https://sqlalche.me/e/20/f405)

但是,如果我在 PyCharm 中打开数据库控制台窗口;将SQL粘贴到异常中;并添加有效的参数值:

SELECT [MySchema].registration.id                        AS [MySchema_registration_id],
       [MySchema].registration.uuid                      AS [MySchema_registration_uuid],
       [MySchema].registration.last_name                 AS [MySchema_registration_last_name],
       [MySchema].registration.first_name                AS [MySchema_registration_first_name],
       [MySchema].registration.email                     AS [MySchema_registration_email],
       [MySchema].registration.phone                     AS [MySchema_registration_phone],
       [MySchema].registration.date_added                AS [MySchema_registration_date_added],
       [MySchema].registration.other_heard_from          AS [MySchema_registration_other_heard_from],
       [MySchema].registration.other_feedback            AS [MySchema_registration_other_feedback],
       COALESCE([MySchema].registration.date_expired, '2024-05-16 16:36:39') AS coalesce_1,
       COALESCE([MySchema].registration.expired_by, '')   AS coalesce_3,
       COUNT([MySchema].school.registration_id)          AS count_1
    FROM [MySchema].registration
             JOIN [MySchema].[user]
                  ON [MySchema].[user].email = [MySchema].registration.email
             LEFT OUTER JOIN [MySchema].school
                             ON [MySchema].school.registration_id = [MySchema].registration.id
    WHERE COALESCE([MySchema].registration.date_expired, '2024-05-16 16:36:39') < '2024-05-16 16:36:39'
    GROUP BY [MySchema].registration.id, 
             [MySchema].registration.uuid, 
             [MySchema].registration.last_name,
             [MySchema].registration.first_name, 
             [MySchema].registration.email, 
             [MySchema].registration.phone,
             [MySchema].registration.date_added, 
             [MySchema].registration.other_heard_from,
             [MySchema].registration.other_feedback, 
             COALESCE([MySchema].registration.date_expired, '2024-05-16 16:36:39'),
             COALESCE([MySchema].registration.expired_by, '')
    HAVING COUNT(COALESCE([MySchema].school.registration_id, -1)) > 0
    ORDER BY [MySchema].registration.date_added DESC

我把 SqlAlchemy 弄乱了什么?

sql-server sqlalchemy flask-sqlalchemy pyodbc
1个回答
0
投票

我把 SqlAlchemy 弄乱了什么?

什么也没有。您遇到了 SQL Server ODBC 中参数化查询的限制。它已在 GitHub here 上进行了讨论。

为了证明这不是 SQLAlchemy 或 pyodbc 的错误,这里是 VBA 中的重现代码。

Const default_expiry = "2024-05-16 16:36:39"
cmd.CommandText = _
    "SELECT id, COALESCE(registration.date_expired, ?) AS coalesce_1 " & _
    "FROM registration " & _
    "GROUP BY id, COALESCE(registration.date_expired, ?)"
cmd.Parameters.Append cmd.CreateParameter("", adVarChar, adParamInput, 30, default_expiry)
cmd.Parameters.Append cmd.CreateParameter("", adVarChar, adParamInput, 30, default_expiry)
    
Dim rst As ADODB.Recordset
Set rst = cmd.Execute

失败

列“registration.date_expired”在选择列表中无效,因为它未包含在聚合函数或 GROUP BY 子句中。

但是,这段代码运行时没有错误:

cmd.CommandText = _
    "SELECT id, COALESCE(registration.date_expired, '2024-05-16 16:36:39') AS coalesce_1 " & _
    "FROM registration " & _
    "GROUP BY id, COALESCE(registration.date_expired, '2024-05-16 16:36:39')"
    
Dim rst As ADODB.Recordset
Set rst = cmd.Execute

将第一个查询转换为 SqlAlchemy

default_expiry = "2024-05-16 16:36:39"
qry = select(
    Registration.id,
    func.coalesce(Registration.date_expired, default_expiry).label(
        "coalesce_1"
    ),
).group_by(
    Registration.id, func.coalesce(Registration.date_expired, default_expiry)
)

产生错误,但使用子查询可以正常工作

default_expiry = "2024-05-16 16:36:39"
subq = select(
    Registration.id,
    func.coalesce(Registration.date_expired, default_expiry).label(
        "coalesce_1"
    ),
).subquery()
qry = select(subq.c.id, subq.c.coalesce_1).group_by(
    subq.c.id, subq.c.coalesce_1
)
© www.soinside.com 2019 - 2024. All rights reserved.