MySQL PHP вставляет новую строку, в которой значения столбцов rowNum всегда остаются хронологическими по дате и времени

#php #mysql #sql

Вопрос:

Я пытаюсь создать SQL-запрос (или несколько запросов и логику в PHP) для вставки новых строк в таблицу базы данных MySQL (скажем, имя таблицы student), где значения столбца rowNum всегда остаются хронологическими в зависимости от отдельного столбца даты/времени. Это означает, что если строка, которую я вставляю, имеет наибольшую/максимальную/последнюю дату/время, она должна быть вставлена нормально, и значение числа строк просто увеличится на единицу. Я уже это реализовал. Проблема в том, что когда строка, которую я вставляю, имеет значение даты/времени, которое находится между двумя существующими строками. Затем значение числа строк для строки, которую я вставляю, должно быть таким же, как значение числа строк для второй из двух строк, которые я пытаюсь вставить «между» (Примечание: я понимаю, что таблица представляет собой неупорядоченный список/набор; однако число строк необходимо отрегулировать, так как в нем вставляется «между»). Затем для остальных строк после (хронологически говоря) этой недавно вставленной строки необходимо увеличить значение номера строки на единицу. Пожалуйста, смотрите пример ниже для дальнейшего разъяснения:

идентификатор-это столбец идентификатора автоинкремента и первичный ключ. rowNum-это «ссылочный» идентификатор, который не обязательно уникален, но увеличивается при каждой новой вставке. Если вы просматриваете каждое значение номера строки, они всегда должны располагаться в хронологическом порядке на основе столбца даты/времени. Дата-время не является меткой времени по умолчанию, вместо этого это поле varchar в формате, показанном ниже.

Таблица: студент

ID роуНум Дата и время
1 4 09-17-2021 14:00
2 5 09-17-2021 16:32
3 6 09-18-2021 19:11
4 7 09-22-2021 13:01

Затем при вставке новой строки с датой и временем: 09-17-2021 15:21 таблица должна быть следующей:

Таблица: студент

ID роуНум Дата и время
1 4 09-17-2021 14:00
5 5 09-17-2021 15:21
2 5 09-17-2021 16:32
3 6 09-18-2021 19:11
4 7 09-22-2021 13:01

Затем значения числа строк после вставленной строки должны увеличиваться следующим образом:

Таблица: студент

ID роуНум Дата и время
1 4 09-17-2021 14:00
5 5 09-17-2021 15:21
2 6 09-17-2021 16:32
3 7 09-18-2021 19:11
4 8 09-22-2021 13:01

Наконец, я понимаю, что это странный поступок. Я ясно выразил эту озабоченность и предложил, чтобы это было сделано по-другому; но из-за уникальных ограничений я должен делать это таким образом, когда значения rowNum являются хронологическими.

Комментарии:

1. » rowNum-это «ссылочный» идентификатор » Ссылка на что? Для чего он используется? Должно ли оно храниться в базе данных? В чем заключается ваш вопрос?

2. Почему бы не использовать ROW_NUMBER() ? (хотя для этого требуется MySQL 8.0.)

3. @brombeer «rowNum» — это просто ссылка на запись в этой строке. Он должен храниться в базе данных. По сути, это «имя» записи, которое будет использоваться в реальном мире для описания данных в этой строке, если это имеет смысл. Например, человек «Билл» мог бы спросить, какова была дата и время, когда произошла запись в rowNum 100? В моей фактической таблице есть несколько других столбцов, заполненных другими данными. Я просто упростил таблицу, чтобы задать вопрос.

4. Кроме того, ваши данные DATETIME имеют недопустимый формат. MySQL использует формат ГГГГ-ММ-ДД для дат. Таким образом, ваши даты на самом деле являются строками, что означает, что они могут вообще не вставляться в качестве дат. Что может помешать кому-то вставить строку с dateTime='banana' помощью ?

5. @brombeer Что касается моего вопроса, я ищу предложения о том, как можно создать такую инструкцию SQL insert или существует ли простой способ сделать это. В своих исследованиях я не нашел других случаев, когда у кого-то была такая же ситуация, как у меня.

Ответ №1:

ВСТАВКА не может изменять другие строки, кроме строк, которые она вставляет. Вы также не можете использовать триггер, потому что триггер не может обновлять одну и ту же таблицу (это может привести к бесконечным циклам).

Поэтому вы должны выполнить инструкцию UPDATE после завершения ВСТАВКИ. Лучше всего, если вы сделаете это в рамках транзакции.

Но на самом деле проще сначала выполнить ОБНОВЛЕНИЕ:

 START TRANSACTION;

UPDATE student SET rowNum=rowNum 1 WHERE rowNum >= 5;

INSERT INTO student SET rowNum=5, dateTime='09-17-2021 15:21';

COMMIT;
 

Лучше сначала выполнить ОБНОВЛЕНИЕ, потому что, если вы сначала ВСТАВИТЕ новую строку, она будет включена в условие ОБНОВЛЕНИЯ.

Это все еще имеет проблему, если несколько клиентов вставляют строку одновременно. Это может привести к конфликтам блокировок или взаимоблокировкам. Возможно, вам придется сначала использовать ТАБЛИЦЫ БЛОКИРОВОК, чтобы предотвратить это. Но это заблокирует вашу возможность выполнять одновременные вставки. Другими словами, каждая транзакция, которая выполняет ВСТАВКУ, должна будет ждать, пока другие совершат ее.

Вам также следует рассмотреть:

  • Что произойдет со значениями числа строк, если строка будет удалена?
  • Что происходит со значениями числа строк, если дата-время обновляется?
  • Что мешает клиенту напрямую обновить значение числа строк и отменить непрерывную последовательность?

Комментарии:

1. Одновременные вставки уже обрабатываются, позволяя одновременно входить только одному пользователю-я знаю, что это своего рода архаичное решение, но оно работает и подходит для моего варианта использования. Я рассмотрю ваше решение и отмечу как ответ, если оно сработает для меня. Оцените предложение рассмотреть возможность удаления/обновления строк.

2. Я не хочу думать о WTFPM вашего приложения.

3. Ха-ха, ну, к сожалению, это делает нас двоих…

4. Таким образом, я смог использовать этот формат, в котором я использовал транзакции, оператор обновления и оператор вставки. Я смог аналогичным образом справиться с ситуациями удаления и обновления. Чтобы найти, где увеличить число строк, начиная с, я выполнил другой запрос: ВЫБЕРИТЕ * У студента, ГДЕ дата инцидента>=’$userInputtedDatetime’ ПОРЯДОК ПО ЧИСЛУ строк, КАК ОГРАНИЧЕНИЕ 1. Затем я сохранил номер строки из этого запроса в параметре phpVariable для использования в моем запросе обновления транзакций (…ГДЕ номер строки >= параметр phpVariable).

5. Кроме того, я изменил свою базу данных, поэтому теперь она использует тип данных datetime вместо varchar, и я изучаю таблицы блокировки для обработки параллелизма, чтобы понять, имеет ли это смысл или это было бы лучшим решением для моего приложения.