"invalid reference to FROM-clause entry for table" 在 Postgres 查询中
"invalid reference to FROM-clause entry for table" in Postgres query
我有以下查询:
query =
"SELECT
data #>> '{id}' AS id,
data #>> '{name}' AS name,
data #>> '{curator}' AS curator,
data #> '{$isValid}' AS \"$isValid\",
data #> '{customer}' AS customer,
data #> '{$createdTS}' AS \"$createdTS\",
data #> '{$updatedTS}' AS \"$updatedTS\",
data #> '{$isComplete}' AS \"$isComplete\",
(count(keys))::numeric as \"numProducts\",
created_at
FROM
appointment_intakes,
LATERAL jsonb_object_keys(data #> '{products}') keys
INNER JOIN
appointment_intake_users
ON
appointment_intake_users.appointment_intake_id = appointment_intakes.id
#{where_clause}
GROUP BY id"
它导致了以下错误:
invalid reference to FROM-clause entry for table "appointment_intakes"
我添加后开始出现错误:
LATERAL jsonb_object_keys(data #> '{products}') keys
和
(count(keys))::numeric as \"numProducts\"
因为我需要计算产品的数量。
如何避免此错误的发生?
错误解释
错误消息的直接原因是任何显式 JOIN
的绑定都比逗号 (,
) 强,否则等同于 CROSS JOIN
,但是 (per documentation):
Note: This latter equivalence does not hold exactly when more than two
tables appear, because JOIN
binds more tightly than comma. For example
FROM T1 CROSS JOIN T2 INNER JOIN T3 ON condition
is not the same as
FROM T1, T2 INNER JOIN T3 ON condition
because the condition
can
reference T1
in the first case but not the second.
粗体 强调我的。
这是你错误的原因。您可以修复它:
FROM appointment_intakes
<b>CROSS JOIN</b> LATERAL jsonb_object_keys(data #> '{products}') keys
INNER JOIN appointment_intake_users ON ...
但这不是唯一的问题。继续阅读。
有人可能会争辩说 Postgres 应该看到 LATERAL
只在与左边的 table 相关时才有意义。但事实并非如此。
假设
我添加了 table 别名,并且 table-qualified 所有列名都是可疑的。在这样做的同时,我简化了 JSON 引用并减少了一些噪音。
此查询仍然不正确:
SELECT i.data ->> 'id' AS id,
i.data ->> 'name' AS name,
i.data ->> 'curator' AS curator,
i.data -> '$isValid' AS "$isValid",
i.data -> 'customer' AS customer,
i.data -> '$createdTS' AS "$createdTS",
i.data -> '$updatedTS' AS "$updatedTS",
i.data -> '$isComplete' AS "$isComplete",
count(k.keys)::numeric AS "numProducts",
u.created_at
FROM appointment_intakes i
, jsonb_object_keys(i.data -> 'products') AS k(keys)
JOIN appointment_intake_users u ON u.appointment_intake_id = i.id
#{where_clause}
GROUP BY i.id
原始查询
基于以上和更多假设,解决方案可能是在子查询中进行计数:
SELECT i.data ->> 'id' AS id,
i.data ->> 'name' AS name,
i.data ->> 'curator' AS curator,
i.data -> '$isValid' AS "$isValid",
i.data -> 'customer' AS customer,
i.data -> '$createdTS' AS "$createdTS",
i.data -> '$updatedTS' AS "$updatedTS",
i.data -> '$isComplete' AS "$isComplete",
(SELECT count(*)::numeric
FROM jsonb_object_keys(i.data -> 'products')) AS "numProducts",
min(u.created_at) AS created_at
FROM appointment_intakes i
JOIN appointment_intake_users u ON u.appointment_intake_id = i.id
-- #{where_clause}
GROUP BY i.id;
因为你只需要count,所以我把你的LATERAL
join转成关联子查询,这样就避免了多个1:n join合并产生的各种问题。更多:
- Two SQL LEFT JOINS produce incorrect result
您需要正确转义标识符,使用准备好的语句并传递values 作为值。不要将值连接到查询字符串中。这是对随机错误或 SQL 注入 攻击的邀请。 PHP 最近的例子:
我有以下查询:
query =
"SELECT
data #>> '{id}' AS id,
data #>> '{name}' AS name,
data #>> '{curator}' AS curator,
data #> '{$isValid}' AS \"$isValid\",
data #> '{customer}' AS customer,
data #> '{$createdTS}' AS \"$createdTS\",
data #> '{$updatedTS}' AS \"$updatedTS\",
data #> '{$isComplete}' AS \"$isComplete\",
(count(keys))::numeric as \"numProducts\",
created_at
FROM
appointment_intakes,
LATERAL jsonb_object_keys(data #> '{products}') keys
INNER JOIN
appointment_intake_users
ON
appointment_intake_users.appointment_intake_id = appointment_intakes.id
#{where_clause}
GROUP BY id"
它导致了以下错误:
invalid reference to FROM-clause entry for table "appointment_intakes"
我添加后开始出现错误:
LATERAL jsonb_object_keys(data #> '{products}') keys
和
(count(keys))::numeric as \"numProducts\"
因为我需要计算产品的数量。
如何避免此错误的发生?
错误解释
错误消息的直接原因是任何显式 JOIN
的绑定都比逗号 (,
) 强,否则等同于 CROSS JOIN
,但是 (per documentation):
Note: This latter equivalence does not hold exactly when more than two tables appear, because
JOIN
binds more tightly than comma. For exampleFROM T1 CROSS JOIN T2 INNER JOIN T3 ON condition
is not the same asFROM T1, T2 INNER JOIN T3 ON condition
because thecondition
can referenceT1
in the first case but not the second.
粗体 强调我的。
这是你错误的原因。您可以修复它:
FROM appointment_intakes
<b>CROSS JOIN</b> LATERAL jsonb_object_keys(data #> '{products}') keys
INNER JOIN appointment_intake_users ON ...
但这不是唯一的问题。继续阅读。
有人可能会争辩说 Postgres 应该看到 LATERAL
只在与左边的 table 相关时才有意义。但事实并非如此。
假设
我添加了 table 别名,并且 table-qualified 所有列名都是可疑的。在这样做的同时,我简化了 JSON 引用并减少了一些噪音。 此查询仍然不正确:
SELECT i.data ->> 'id' AS id,
i.data ->> 'name' AS name,
i.data ->> 'curator' AS curator,
i.data -> '$isValid' AS "$isValid",
i.data -> 'customer' AS customer,
i.data -> '$createdTS' AS "$createdTS",
i.data -> '$updatedTS' AS "$updatedTS",
i.data -> '$isComplete' AS "$isComplete",
count(k.keys)::numeric AS "numProducts",
u.created_at
FROM appointment_intakes i
, jsonb_object_keys(i.data -> 'products') AS k(keys)
JOIN appointment_intake_users u ON u.appointment_intake_id = i.id
#{where_clause}
GROUP BY i.id
原始查询
基于以上和更多假设,解决方案可能是在子查询中进行计数:
SELECT i.data ->> 'id' AS id,
i.data ->> 'name' AS name,
i.data ->> 'curator' AS curator,
i.data -> '$isValid' AS "$isValid",
i.data -> 'customer' AS customer,
i.data -> '$createdTS' AS "$createdTS",
i.data -> '$updatedTS' AS "$updatedTS",
i.data -> '$isComplete' AS "$isComplete",
(SELECT count(*)::numeric
FROM jsonb_object_keys(i.data -> 'products')) AS "numProducts",
min(u.created_at) AS created_at
FROM appointment_intakes i
JOIN appointment_intake_users u ON u.appointment_intake_id = i.id
-- #{where_clause}
GROUP BY i.id;
因为你只需要count,所以我把你的LATERAL
join转成关联子查询,这样就避免了多个1:n join合并产生的各种问题。更多:
- Two SQL LEFT JOINS produce incorrect result
您需要正确转义标识符,使用准备好的语句并传递values 作为值。不要将值连接到查询字符串中。这是对随机错误或 SQL 注入 攻击的邀请。 PHP 最近的例子: