INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
Обновление и добавление записи одной конструкцией на MySQL возможно?
таблицы InnoDB
1. нужно сделать следующее - попытаться добавить запись, если вдруг есть совпадения с каким-нибудь уникальным полем, то вместо добавления выполнить обновление записи, причём сделать это надо как-то наиболее оптимально в одной конструкции...
Replace не предлагать - replace вобще не вариант по понятным причинам...
-----------------------
2. Если решений реализовать п1. в мускуле нет - тогда другой вопрос:
Если использовать insert ignore into... - как узнать выполнился insert или insert был проигнорен? (При этом желательно не делая никаких отдельных селектов на получение максимального значения Id записи до и после инсерта).
ON DUPLICATE KEY UPDATE в конструкции INSERT:
[highlight=sql]
INSERT
`Table` (`id`,`field`)
VALUES (1,'Text')
ON DUPLICATE KEY UPDATE `Table`
SET
`Text`='NewText'
WHERE
`id`=1
[/highlight]
Используйте
[highlight=sql]
INSERT
`Table` (`id`,`field`)
VALUES (1,'Text')
ON DUPLICATE KEY UPDATE `Table`
SET
`Text`='NewText'
WHERE
`id`=1
[/highlight]
Код:
И в MySQl ещё ко всему процчему нету вообще конструкции update-а из select-а... :(
Вообще всё больше складывается впечатление, что на этой СУБД можно только для детсадовских приложений писать :(
------------------
Судя по всему актуальным становится вопрос 2.
ну а если выполнить задачу в 2 этапа? Для начала создать VIEW и заполнить его результатом SELECT, в условии которого будет указано, не выбирать существующие записи в целевой таблице. Вторым этапом заполнить целевую таблицу из VIEW?
Впрочем погорячился я со VIEW, достаточно просто в INSERT ... SELECT в условии выборки SELECT исключать имеющиеся записи в целевой таблице
у нас делается что то подобное. реализовывали так: копируются данные во временную таблицу. затем данные из временной таблицы сравниваются с данными в таблице назначения. при совпадении записей полностью, напротив соответствующих во временной таблице ставится флаг, типа set flag = '***', где флаг - это поле. при совпадении уникальных полей то же самое, только во флаг записывается ID записи из таблицы назначения. а при полном несовпадении ничего не ставится. а потом делаются Update'ы и инсерты в зависимости от поля flag. это возможно, громоздкое решение, но у нас так.
Код:
insert ignore into Passport
(
Id
, PassportOwnerId
, PassportRegistrationAddressId
, Name
, Surname
, PatronymicName
, PassportSeria
, PassportNumber
, PassportOffice
, PassportDate
, WhenAdd
)
select
passport.Id
, passport_composes.PassportOwnerId
, passport_composes.PassportRegistrationAddressId
, passport_composes.PersonName
, passport_composes.PersonSurname
, passport_composes.PersonPatronymicName
, passport_composes.PassportSeria
, passport_composes.PassportNumber
, passport_composes.PassportOffice
, passport_composes.PassportDate
, case when passport.WhenAdd is null then now()
else passport.WhenAdd
end
from
(select
person_id PassportOwnerId
, address.Id PassportRegistrationAddressId
, person_name PersonName
, person_surname PersonSurname
, person_patronymic_name PersonPatronymicName
, passport_seria PassportSeria
, passport_number PassportNumber
, passport_office PassportOffice
, passport_date PassportDate
from
(select
passport_city_id CityId
, passport_street_name StreetName
, passport_house_number HouseNumber) as address_composes
left join Address address
on address_composes.CityId = address.CityId
and address_composes.StreetName = address.StreetName
and address_composes.HouseNumber = address.HouseAndBlockNumber) as passport_composes
left join Passport passport
on passport.PassportOwnerId = passport_composes.PassportOwnerId
where
passport_composes.PassportRegistrationAddressId is not null
and (not exists(
select
1
from
vwPassport vw_passport
where
vw_passport.PassportSeria = passport_composes.PassportSeria
and vw_passport.PassportNumber = passport_composes.PassportNumber)
or passport.Id is not null);
(
Id
, PassportOwnerId
, PassportRegistrationAddressId
, Name
, Surname
, PatronymicName
, PassportSeria
, PassportNumber
, PassportOffice
, PassportDate
, WhenAdd
)
select
passport.Id
, passport_composes.PassportOwnerId
, passport_composes.PassportRegistrationAddressId
, passport_composes.PersonName
, passport_composes.PersonSurname
, passport_composes.PersonPatronymicName
, passport_composes.PassportSeria
, passport_composes.PassportNumber
, passport_composes.PassportOffice
, passport_composes.PassportDate
, case when passport.WhenAdd is null then now()
else passport.WhenAdd
end
from
(select
person_id PassportOwnerId
, address.Id PassportRegistrationAddressId
, person_name PersonName
, person_surname PersonSurname
, person_patronymic_name PersonPatronymicName
, passport_seria PassportSeria
, passport_number PassportNumber
, passport_office PassportOffice
, passport_date PassportDate
from
(select
passport_city_id CityId
, passport_street_name StreetName
, passport_house_number HouseNumber) as address_composes
left join Address address
on address_composes.CityId = address.CityId
and address_composes.StreetName = address.StreetName
and address_composes.HouseNumber = address.HouseAndBlockNumber) as passport_composes
left join Passport passport
on passport.PassportOwnerId = passport_composes.PassportOwnerId
where
passport_composes.PassportRegistrationAddressId is not null
and (not exists(
select
1
from
vwPassport vw_passport
where
vw_passport.PassportSeria = passport_composes.PassportSeria
and vw_passport.PassportNumber = passport_composes.PassportNumber)
or passport.Id is not null);
Тока мне кроме этого нужно ещё Update сделать,в том случае если запись не добавилась из-за ограничения уникального ключа PassportOwnerId - только вот UPDATE-а из селекта нефига нету :(
И как всётаки узнать выполнился insert или проигнорился - это ведь наверно как-то можно...
На самом деле on duplicate key очень рульная конструкция и с insert ... select она тоже работает, только оноа не многа не такая как писал Romik - не надо ни таблицу указывать, ни условие where - обновляются сразу поля той записи из-за котрой инсерт не удался.
Вообще сделал вот так и запахало как надо:
Фрагмент запроса:
Код:
insert into Passport
(
Id
, PassportOwnerId
, PassportRegistrationAddressId
, Name
, Surname
, PatronymicName
, PassportSeria
, PassportNumber
, PassportOffice
, PassportDate
, WhenAdd
)
select
....
from
...
where
passport_composes.PassportRegistrationAddressId is not null
and (not exists(
select
1
from
vwPassport vw_passport
where
vw_passport.PassportSeria = passport_composes.PassportSeria
and vw_passport.PassportNumber = passport_composes.PassportNumber)
or passport.Id is not null)
on duplicate key update
PassportRegistrationAddressId = passport_composes.PassportRegistrationAddressId
, Name = passport_composes.PassportName
, Suranme = passport_composes.PassportSurname
, ... ;
(
Id
, PassportOwnerId
, PassportRegistrationAddressId
, Name
, Surname
, PatronymicName
, PassportSeria
, PassportNumber
, PassportOffice
, PassportDate
, WhenAdd
)
select
....
from
...
where
passport_composes.PassportRegistrationAddressId is not null
and (not exists(
select
1
from
vwPassport vw_passport
where
vw_passport.PassportSeria = passport_composes.PassportSeria
and vw_passport.PassportNumber = passport_composes.PassportNumber)
or passport.Id is not null)
on duplicate key update
PassportRegistrationAddressId = passport_composes.PassportRegistrationAddressId
, Name = passport_composes.PassportName
, Suranme = passport_composes.PassportSurname
, ... ;
Запросы с on duplicate key такие компактные получаются на них даже смотреть приятно становится :)