Ошибка синтаксиса при динамических множественных обновлениях

Вопрос или проблема

Получение 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 *;`;
};

Возможные причины ошибок

  1. Ошибка в VALUES: Убедитесь, что переданные значения в VALUES форматируются правильно. Ваша запись должна содержать скобки для каждого набора значений.

  2. Обращение к excluded: Обратите внимание, что при использовании конструкции FROM, вы должны ссылаться на excluded непосредственно, как это сделано в вашем примере.

  3. Проверка на существование записей: Перед выполнением обновления убедитесь, что ваши данные корректны и содержат нужные поля, особенно id, чтобы избежать неожиданных ошибок.

Заключение

Попробуйте использовать предложенный код и следите за тем, чтобы переданные данные соответствовали ожидаемому формату. Если после этого ошибка остается, внимательно проверьте структуру массива matches и сами значения, которые вы передаете в запрос.

Оцените материал
Добавить комментарий

Капча загружается...