Почему я получаю ErrNoRows("sql: нет строк в наборе результатов") после вставки в postgres, даже если вставка была действительно успешной?

Я работаю с golang-postgres:

"database/sql"
_ "github.com/lib/pq"

Что я делаю:

Я запускаю запрос выбора. Если я не получу ни одной записи по выбору, я добавлю ее. Еще, обновить или что-то еще...

Проблема в том, что каждый раз, когда вставка возвращает ErrNoRows("sql: нет строк в наборе результатов"), даже когда я вижу в базе данных, что INSERT был успешным, и строка была добавлена.

Кроме того, lastInsertID всегда остается 0, а если я проверяю в БД, он имеет фактическое значение (скажем, 131)

Кажется, что ошибка рядом с комментарием 2 ниже в коде, где-то кешируется и снова появляется.

// 1. Select first
sQueryStmt, sPrepErr := db.Prepare(selectQuery)
    if sPrepErr != nil {
        glog.V(3).Infof("selectQuery prepare failed. err: %v", sPrepErr)
        return sPrepErr
    }

    queryErr := sQueryStmt.QueryRow(today, itemID).Scan(&a, &b, &c, &d, &e, &f, &g, &h, &i, &j)
    if queryErr != nil {

// 2. Getting ErrNoRows here is expected, for the first entry
        if queryErr == sql.ErrNoRows {
            glog.V(3).Infof("selectQuery returned no results. err: %v", queryErr)

            var lastInsertID int
            iQueryStmt, iPrepErr := db.Prepare(insertQuery)
            if iPrepErr != nil {
                glog.V(3).Infof("insertQuery prepare failed. err: %v", iPrepErr)
                return iPrepErr
            }
            insertErr := iQueryStmt.QueryRow(today, today, today, taskID).Scan(&lastInsertID)
            if insertErr != nil {
                // 3. Somehow, even after row is correctly being created, I am getting insertErr as "sql: no rows in result set" here
                glog.V(3).Infof("insertQuery failed. err: %v", insertErr)
            } else {
// control never comes to this part.
                glog.V(3).Infof("insertQuery Successful. lastInsertID: %v", lastInsertID)
            }
        } else {
            glog.V(3).Infof("Couldn't run query on Postgres database. err: %v", queryErr)
            return queryErr
        }
}

Отладка в базе данных / sql, показывает, что она возвращает эту ошибку в блоке кода ниже:

    if !r.rows.Next() {
        if err := r.rows.Err(); err != nil {
            return err
        }
        return ErrNoRows
    }

Но каждый раз, когда я проверяю в БД, данные всегда уже вставляются.

Редактировать:

selectQuery = `select task_id, creation_date, times_x_ran,
                        a_count, b_count, c_count, d_count, e_count 
                        from reports where creation_date = $1 and task_id = $2`

insertQuery = `insert into reports 
                (creation_date, creation_time, last_modified, task_id, times_x_ran, times_y_ran, a, b, c, d, e, x_errors, y_errors) 
                    values 
                    ($1, $2, $3, $4,
                    1, 0, 
                    0, 0, 0, 0, 0, 
                    '', '' )`

1 ответ

Решение

Вы фактически задали два вопроса, поэтому я отвечу на оба:

  1. Почему ErrNoRows, даже если ваша вставка прошла успешно?

    Это ожидаемое поведение, потому что по умолчанию INSERT не возвращает строк. Ваша "ошибка" на самом деле не является проблемой. Если вы хотите, чтобы INSERT возвращал строки, вы должны использовать предложение 'RETURNING' в конце.

    Тот факт, что состояние "Нет строк в наборе результатов" сообщается из-за ошибки, может быть причиной вашей путаницы. Но это следует считать ошибкой, только если вы ожидали строки.

  2. Также lastInsertID всегда остается 0.

    Это тоже ожидаемое поведение. Как задокументировано:

    pq не поддерживает метод LastInsertId() типа Result в базе данных /sql. Чтобы вернуть идентификатор INSERT (или UPDATE или DELETE), используйте предложение Postgres RETURNING со стандартным вызовом Query или QueryRow:

Другие вопросы по тегам