Вопрос или проблема
Получение PostgresError: ошибка синтаксиса в этом запросе:
exports.updateMatches = async ({ payload: { matches } }) => {
const formattedMatches = objArrToArr(matches);
const cols = Object.keys(matches[0]);
const colsWOId = cols
.filter((item) => item !== "id")
.map((item) => camelToSnake(item));
return await sql`
update matches
set ${colsWOId.map((col) => `${sql(col)} = excluded.${sql(col)}`).join(", ")}
from (values ${sql(formattedMatches)}) as excluded(${cols.join(", ")})
where matches.id = (excluded.id):: int
returning *;`;
};
замечание: используется пакет postgres npm, они не поддерживают sql.identifier()/sql.raw(). пытался следовать формату sql из их официальной документации:
Несколько обновлений в одном запросе:
const users = [
[1, 'John', 34],
[2, 'Jane', 27],
]
await sql`
update users set name = update_data.name, age = (update_data.age)::int
from (values ${sql(users)}) as update_data (id, name, age)
where users.id = (update_data.id)::int
returning users.id, users.name, users.age
`
Детали ошибки из библиотеки:
PostgresError: ошибка синтаксиса около "FROM"
at ErrorResponse (/home/raf/apps/tourna-pro/api/node_modules/postgres/cjs/src/connection.js:788:26)
at handle (/home/raf/apps/tourna-pro/api/node_modules/postgres/cjs/src/connection.js:474:6)
at Socket.data (/home/raf/apps/tourna-pro/api/node_modules/postgres/cjs/src/connection.js:315:9)
at Socket.emit (node:events:519:28)
at addChunk (node:internal/streams/readable:559:12)
at readableAddChunkPushByteMode (node:internal/streams/readable:510:3)
at Readable.push (node:internal/streams/readable:390:5)
at TCP.onStreamRead (node:internal/stream_base_commons:191:23)
at cachedError (/home/raf/apps/tourna-pro/api/node_modules/postgres/cjs/src/query.js:170:23)
at new Query (/home/raf/apps/tourna-pro/api/node_modules/postgres/cjs/src/query.js:36:24)
at sql (/home/raf/apps/tourna-pro/api/node_modules/postgres/cjs/src/index.js:112:11)
at exports.updateMatches (/home/raf/apps/tourna-pro/api/src/service/tournament-format.js:139:24)
severity_local: 'ERROR',
severity: 'ERROR',
code: '42601',
position: '148',
file: 'scan.l',
line: '1242',
routine: 'scanner_yyerror'
Ответ или решение
Ваша проблема возникает из-за неправильного синтаксиса в вашем SQL-запросе для обновления нескольких записей. Давайте разберемся с вашим кодом и выявим, как его можно исправить.
Проблема
Ошибка PostgresError: syntax error at or near "FROM"
указывает на то, что SQL-синтаксис в вашей строке запроса неправилен, особенно в части FROM
. По всей видимости, проблема заключается в том, как формируется подзапрос с использованием VALUES
.
Исправленный пример кода
Судя по вашему примеру с пользователями, вот как можно переписать вашу функцию updateMatches
для правильной работы с PostgreSQL. Убедитесь, что строка, передаваемая в sql
, правильно формируется и что порядок операций SQL соблюдается.
exports.updateMatches = async ({ payload: { matches } }) => {
const formattedMatches = objArrToArr(matches);
const cols = Object.keys(matches[0]);
const colsWOId = cols
.filter((item) => item !== "id")
.map((item) => camelToSnake(item));
return await sql`
UPDATE matches
SET ${sql(colsWOId.map((col, index) => `${sql(col)} = excluded.${sql(col)}`))}
FROM (VALUES ${sql(formattedMatches.map(match => `(${cols.map((col) => match[col]).join(", ")})`))}) AS excluded(${cols.join(", ")})
WHERE matches.id = excluded.id::int
RETURNING *;`;
};
Возможные причины ошибок
-
Ошибка в
VALUES
: Убедитесь, что переданные значения вVALUES
форматируются правильно. Ваша запись должна содержать скобки для каждого набора значений. -
Обращение к
excluded
: Обратите внимание, что при использовании конструкцииFROM
, вы должны ссылаться наexcluded
непосредственно, как это сделано в вашем примере. -
Проверка на существование записей: Перед выполнением обновления убедитесь, что ваши данные корректны и содержат нужные поля, особенно
id
, чтобы избежать неожиданных ошибок.
Заключение
Попробуйте использовать предложенный код и следите за тем, чтобы переданные данные соответствовали ожидаемому формату. Если после этого ошибка остается, внимательно проверьте структуру массива matches
и сами значения, которые вы передаете в запрос.