Дубликат ключа нарушает уникальное ограничение - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть история таблиц, в которую я записываю журналы.

Когда я хочу вставить журнал, я получаю сообщение об ошибке:

23505: дубликат ключа нарушает уникальное ограничение!

Вот моя функция

public static void InsertLog(JobLogs log)
{
        using (NpgsqlConnection con = new NpgsqlConnection(AppForms.connectionString))
        {
            string insert = "Insert into jat.history Values (@jobid, @year, @number, @datetime, @operator, @activity, @desc, nextval('jat.history_h_id_seq'))";
            using (NpgsqlCommand cmd = new NpgsqlCommand(insert, con))
            {
                //MessageBox.Show(insert);
                con.Open();

                cmd.Parameters.AddWithValue("@jobid", log.JobId);
                cmd.Parameters.AddWithValue("@year", log.jobMark.Year);
                cmd.Parameters.AddWithValue("@number", log.jobMark.JobNumber);
                cmd.Parameters.AddWithValue("@datetime", log.Time);
                cmd.Parameters.AddWithValue("@operator", log.Operator.GetFullName());
                cmd.Parameters.AddWithValue("@activity", log.Activity);
                cmd.Parameters.AddWithValue("@desc", DBNull.Value);

                cmd.ExecuteNonQuery();
            }

        }

    }

История таблицы имеет только один первичный ключ, и это -> h_id.Когда я меняю запрос на вставку следующим образом:

 string insert = "Insert into jat.history Values(@jobid, @year, @number, @datetime, @operator, @activity, @desc, (select max(h_id) + 1 from jat.history))";

Он работает правильно, но я слышал, что я должен использовать последовательности в многопользовательских приложениях, так что не так с моей первой функцией и первым запросом?

РЕДАКТИРОВАТЬ :
Когда я запускаю эти два запроса в соответствии с рекомендациями, я получаю следующие результаты:

" (SELECT last_value FROM jat.history_h_id_seq)"; -- result:282

"SELECT (SELECT MAX(h_id) FROM jat.history)"; -- result:290

1 Ответ

0 голосов
/ 02 декабря 2018

В вашем определении таблицы поле h_id равно h_id serial NOT NULL.Бит serial означает, что для этого поля была создана последовательность, так что каждый раз, когда вы вставляете новую запись в эту таблицу, поле h_id по умолчанию будет иметь значение nextval('jat.history_h_id_seq').

Когда поле настроено таким образом, в большинстве случаев вам никогда не следует вручную указывать это поле и значение в команде INSERT, потому что это означает, что nextval('jat.history_h_id_seq') не будет вызываться и увеличиваться, что может вызвать проблемы, которые выВы испытываете.


Например, давайте создадим новую таблицу: CREATE TABLE t (id SERIAL PRIMARY KEY, txt TEXT);.Последовательность с именем schema_name.t_id_seq будет автоматически создана вместе с таблицей.Я также поместил первичный ключ в id, так как это также PK вашей таблицы.

Теперь вставьте новую запись правильно: INSERT INTO t (txt) VALUES ('hello'); Это создаст запись, содержащую значения id: 1, txt: 'hello'.Я вообще не указал id, но он автоматически получил значение 1. Если я вставлю другую запись таким же образом, id новой записи будет 2.

Вместо этого я будуневерно вставить новую запись: INSERT INTO t (id, txt) VALUES (2, 'bye');.Это работает нормально, но я вручную установил значение id, что означает, что последовательность не использовалась, поэтому ее «следующее значение» по-прежнему равно 2. Теперь, если я правильно вставлю другую запись: INSERT INTO t (txt) VALUES ('test');, она не будет выполнена суникальная ошибка нарушения, потому что он пытается использовать nextval значение последовательности (2) для id, но запись с таким идентификатором уже существует, потому что я указал это поле вручную.


В любом случае этопроблема с вашими данными.И согласно запросам, которые вы выполнили, чтобы получить MAX(h_id) из вашей таблицы и значение last_value из вашей последовательности, у вас в таблице более высокие идентификаторы, чем у вашей последовательности, тогда как самый высокий идентификатор в вашей таблице должен быть таким жекак (или ниже) вашей последовательности last_value.

Чтобы исправить это, сначала обновите последовательность до максимального идентификатора из вашей таблицы: SELECT SETVAL('jat.history_h_id_seq', (SELECT MAX(h_id) FROM jat.history));

Это обновит текущую вашу последовательностьзначение самого высокого идентификатора в вашей таблице, поэтому при следующем использовании последовательности следующий идентификатор (последний / текущий + 1) будет больше, чем что-либо в вашей таблице, поэтому не будет дубликатом.

И вторая часть - убедиться, что вы никогда не указали h_id в любом операторе вставки.Просто позвольте ему автоматически получить следующее значение из последовательности.В противном случае вы снова столкнетесь с этой проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...