使用 PDO 在 PostgreSQL 中针对 JSON 键抛出 "must appear in the GROUP BY clause" 的准备语句

Prepared statements against a JSON key throwing "must appear in the GROUP BY clause" in PostgreSQL using PDO

我正在尝试按 json 键动态分组以找到平均答案。

select
   tbl.data->>'Example' as response,
   count(tbl.data->>'Example') as total
from table tbl
group by tbl.data->>'Example'
order by total
limit 1

这个查询在 Postgre运行 内部时工作正常SQL,我得到了我的预期结果:

|     response   |  total  |
|--------------------------|
|  Hello World   |    4    |

当我不知道密钥时,就会出现这个问题。它们是动态创建的,因此我需要遍历它们。

$sql = <<<END
    select
       tbl.data->>? as response,
       count(tbl.data->>?) as total
    from table tbl
    group by tbl.data->>?
    order by total
    limit 1
END;

$stmt = (new \PDO(...))->Prepare($sql);
$stmt->execute(array_fill(1, 3, 'Example'));
$stmt->fetch(\PDO::FETCH_ASSOC);

'Example' 来自用户输入。 JSON 由用户创建,键可以是任何东西。在这种情况下,它是硬编码的,但我 运行 一个单独的 SQL 查询来获取所有键并循环遍历它们:

但我总是得到以下错误:

tbl.data must appear in the GROUP BY clause or be used in an aggregate function

现在,我假设这是因为准备好的语句将列视为数据,但此信息源自用户输入,因此我需要使用准备好的语句。

select json_object_keys(data) as keys from table

想知道如何解决这个问题吗?

我不知道 Php。但是从这个 link(https://kb.objectrocket.com/postgresql/postgres-stored-procedure-call-in-php-1475) 看来,在 php.

中使用函数似乎还可以

demo


CREATE OR REPLACE FUNCTION find_answer (_key text)
    RETURNS json
    AS $$
DECLARE
    is_exists boolean;
    _sql text;
    _return json;
BEGIN
    _sql := $sql$
    SELECT
        row_to_json(cte.*)
    FROM (
        SELECT
            tbl.data ->>  AS response,
            count(tbl.data ->> ) AS total
        FROM
            tbl
        GROUP BY
            1
        ORDER BY
            total DESC
        LIMIT 1) cte $sql$;
    SELECT
        (data[_key] IS NULL) INTO is_exists
    FROM
        tbl;
    IF is_exists THEN
        RAISE EXCEPTION '% not exists.', _key;
    ELSE
        RAISE NOTICE '% sql', _sql;
        EXECUTE _sql
        USING _key INTO _return;
        RETURN _return;
    END IF;
END
$$
LANGUAGE plpgsql;

然后调用它。 select * from find_answer('example');


关于预处理语句

Prepared statements only last for the duration of the current database session. When the session ends, the prepared statement is forgotten, so it must be recreated before being used again. This also means that a single prepared statement cannot be used by multiple simultaneous database clients; however, each client can create their own prepared statement to use. Prepared statements can be manually cleaned up using the DEALLOCATE command.