Вставьте данные и заполните столбцы рангом

исходные данные: original_table

MID STATE CALL_TIME         RECORD_RANK
a   1    2020-12-18 09:00:00        1
a   2    2020-12-19 09:00:00        2
b   1    2020-12-18 09:00:02        1
c   1    2020-12-18 09:00:03        1
c   1    2020-12-19 09:00:03        2
c   1    2020-12-20 09:00:03        3
d   1    2020-12-19 09:00:00        1

Данные, которые я хотел вставить: insert_table

   MID  STATE      CALL_TIME  
   a    2     2020-12-30 09:00:00      
   b    2     2020-12-19 09:00:02   
   c    1     2020-12-21 09:00:03 
   e    1     2020-12-30 09:00:00 
   f    1     2020-12-30 09:00:00 
   f    2     2020-12-31 09:00:00

Цель

  • Исходные данные будут вставлены из вторых данных.
  • Для исходных и вставленных данных пара MID and CALL_TIME уникальна.
  • Во вставленных данных нет столбца RECORD_RANK, но RECORD_RANK будет рассчитываться на основе MID and CALL_TIME columns при вставке. При дублировании MID с другим CALL_TIME значение RECORD_RANK с MID будет добавлено на 1. Начальное значение равно 1.
  • Самая ранняя строка в таблице insert_table всегда позже последней строки в таблице orginal_table с тем же самым MID.

Ожидаемый результат примера, как показано ниже:

MID  STATE      CALL_TIME         RECORD_RANK
a    1    2020-12-18 09:00:00        1
a    2    2020-12-19 09:00:00        2
b    1    2020-12-18 09:00:02        1
c    1    2020-12-18 09:00:03        1
c    1    2020-12-19 09:00:03        2
c    1    2020-12-20 09:00:03        3
d    1    2020-12-19 09:00:00        1
a    2    2020-12-30 09:00:00        3
b    2    2020-12-19 09:00:02        2  
c    1    2020-12-21 09:00:03        4
e    1    2020-12-30 09:00:00        1
f    1    2020-12-30 09:00:00        1 
f    2    2020-12-31 09:00:00        2

Примечание

  • версия mysql: 5.5.47-log

Если call_time всегда увеличивается, я не вижу необходимости хранить record_rank. Просто рассчитайте, когда вам это нужно

Strawberry 21.12.2020 09:52

Между прочим, по соглашению термин «id» подразумевает суррогатный ПЕРВИЧНЫЙ КЛЮЧ. Это не тот случай, поэтому, возможно, стоит переименовать этот столбец.

Strawberry 21.12.2020 09:54

@ArunPalanisamy Нет, любое значение идентификатора может быть продублировано.

Jack 21.12.2020 09:55

@Strawberry, я изменил «ID» на «MID».

Jack 21.12.2020 09:56

Всегда ли самая ранняя строка в insert_table позже последней строки в orginal_table с тем же MID? то есть значения RECORD_RANK, уже присутствующие в orginal_table, никогда не будут пересчитываться?

Akina 21.12.2020 10:10

@Akina да, самая ранняя строка в insert_table всегда позже последней строки в orginal_table с тем же MID.

Jack 22.12.2020 00:58

Возможно, что еще более важно, триггер Акины дает возможность установить MID на будущее INSERTs. (Он не заботится об изменении ранга из-за удаления или обновления.)

Rick James 23.12.2020 18:53
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
5
7
473
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если самая первая строка в insert_table всегда позже последней строки в orginal_table с тем же MID, вы можете использовать триггер BEFORE INSERT:

CREATE TRIGGER tr_bi_original
BEFORE INSERT
ON orginal_table
FOR EACH ROW
SET NEW.RECORD_RANK = (SELECT COALESCE(COUNT(*), 0) + 1
                       FROM orginal_table
                       WHERE NEW.MID = orginal_table.MID)

После создания триггера вы можете просто добавить новые строки,

INSERT INTO orginal_table
SELECT *, NULL FROM insert_table;

Новые значения для RECORD_RANK будут добавлены триггером.

рабочий пример


Если строки из обеих таблиц будут смешиваться и RECORD_RANK для некоторых строк, которые уже присутствуют в orginal_table, необходимо изменить, то операцию нельзя выполнить с помощью одного запроса (поскольку требуется как вставка для новых строк, так и обновление для существующих). В этом случае я рекомендую вставить строки с любым (NULL) значением для столбца RECORD_RANK, а затем пересчитать значение столбца для всех строк в таблице.

Я думаю, мы просто видим это по-разному

Strawberry 21.12.2020 11:00

Почему? ОП будет работать по принципу предвзятости подтверждения.

Strawberry 21.12.2020 11:48

@ Акина, нужно ли использовать триггер?

Jack 22.12.2020 00:59

@jack Нет, конечно, вы можете использовать любой другой метод. Но его использование упрощает процесс, кажется.

Akina 22.12.2020 10:03

@Akina - Ваша техника тесака может быть улучшена, если заменить COUNT(*) на MAX(mid)?

Rick James 23.12.2020 18:55

@РикДжеймс ??? ... рабочий пример доступна - вы можете попробовать.

Akina 23.12.2020 19:50

@Akina «INSERT INTO orginal_table» без (column1, column2, column3, ...) кажется рискованным, если я просто хочу вставить определенные столбцы, такие как скрипт GMB. А я не знаю вашего скрипта, потому что не умею пользоваться триггером. Не могли бы вы объяснить это?

Jack 30.12.2020 09:45

@Jack кажется рискованным. Если ваши данные для вставки могут быть неправильными (могут иметь неправильную структуру), добавьте список столбцов - никаких проблем. Я не знаю, как использовать триггер. Скрипка полностью это демонстрирует. Пожалуйста, не задавайте общий вопрос, указывайте на непонятное для вас место.

Akina 30.12.2020 09:53
Ответ принят как подходящий

Я думаю, что можно обрабатывать логику в одном insert, даже в MySQL 5.x.

Целевой ранг — это количество строк, которые уже существуют в целевой таблице для одного и того же mid, плюс количество mid строк в исходной таблице до текущей строки. Вы можете вычислить это с помощью коррелированных подзапросов:

insert into orginal_table (mid, state, call_time, record_rank)
select mid, state, call_time,
    1 + (
        select count(*)
        from orginal_table o
        where o.mid = i.mid
    ) + (
        select count(*) 
        from insert_table i1 
        where i1.mid = i.mid and i1.call_time < i.call_time
    ) as record_rank
from insert_table i

Это предполагает, что все новые строки являются более новыми, чем существующие строки, как указано в вашем вопросе. Но если вы хотите иначе, это легко исправить в первом подзапросе:

(
    select count(*)
    from orginal_table o
    where o.mid = i.mid and o.call_time < i.call_time
)

Вот демо, основанное на хорошем тестовом примере, созданном Akina.

Примечание: в MySQL 8.0 вместо второго подзапроса мы использовали оконную функцию, что сделало бы запрос более эффективным:

insert into orginal_table (mid, state, call_time, record_rank)
select mid, state, call_time,
    row_number() over(partition by mid order by call_time) 
    + (
        select count(*)
        from orginal_table o
        where o.mid = i.mid
    ) as record_rank
from insert_table i

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