Запрос — заменить или вставить

Den1xxx

Постоялец
Регистрация
15 Янв 2014
Сообщения
289
Реакции
161
Здравствуйте.
Чего-то не соображу, помогите пожалуйста.
При парсинге из 1С заношу товары во временную таблицу, выбирая определённый склад.
Структура временной таблицы
Код:
CREATE TABLE `import_items` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Номер записи',
  `item_id` varchar(11) NOT NULL COMMENT 'Ид товара сайта',
  `item_id_1c` varchar(255) NOT NULL COMMENT 'Ид товара 1С',
  `cat_id_1c` varchar(255) NOT NULL COMMENT 'Ид категории 1С',
  `name` varchar(255) NOT NULL COMMENT 'Имя объекта',
  `price` varchar(25) DEFAULT NULL COMMENT 'Цена оптовая',
  `price1` varchar(25) DEFAULT NULL COMMENT 'Цена 1 дилера',
  `price2` varchar(25) DEFAULT NULL COMMENT 'Цена 2 дилера',
  `price3` varchar(25) DEFAULT NULL COMMENT 'Цена 3 дилера',
  `price4` varchar(25) DEFAULT NULL COMMENT 'Цена 4 дилера',
  `avail_1c` varchar(255) NOT NULL COMMENT 'Статус',
  `quantity` varchar(25) NOT NULL COMMENT 'Количество',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1215 DEFAULT CHARSET=utf8 COMMENT='Объекты для записи каталога из 1С'
Всё ок.

Теперь из временной таблицы нужно перенести в склады.
Структура таблицы складов
Код:
CREATE TABLE `store` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Номер записи',
  `item_id` varchar(11) NOT NULL COMMENT 'Ид товара сайта',
  `name` varchar(255) NOT NULL COMMENT 'Имя объекта',
  `store` int(5) NOT NULL COMMENT 'Номер склада',
  `code_1c` varchar(255) DEFAULT NULL,
  `price` varchar(255) DEFAULT NULL COMMENT 'Цена',
  `price1` varchar(255) DEFAULT NULL COMMENT 'Цена 1',
  `price2` varchar(255) DEFAULT NULL COMMENT 'Цена 2',
  `price3` varchar(255) DEFAULT NULL COMMENT 'Цена 3',
  `price4` varchar(255) DEFAULT NULL COMMENT 'Цена 4',
  `quantity` float DEFAULT NULL COMMENT 'Количество',
  `date` datetime NOT NULL COMMENT 'Время изменения',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Склад'

При вставке в `store` мы одним запросом хотим вставить всё напарсенное из временной таблицы, т.е. например поле store=1
Как сделать запрос: если в таблице `store` уже есть значение поля store=1 и item_id совпадает с временной таблицей, то обновить значения, иначе — вставить новое?
Чего-то торможу, голову сломал уже.
 

starwanderer

Хранитель порядка
Команда форума
Модератор
Регистрация
20 Ноя 2016
Сообщения
1.571
Реакции
3.249
Делайте SELECT и INSERT без указания автоинкрементного поля (Id), оно само проставится.
Как-то перед Новым годом, я так же перегрелся и тормозил.
 

Den1xxx

Постоялец
Регистрация
15 Янв 2014
Сообщения
289
Реакции
161
Все равно чего-то не получается.
Я изменил таблицу Складов
Добавил индекс по 2 полям.
Теперь она выглядит так
Код:
CREATE TABLE `store` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Номер записи',
  `item_id` int(5) NOT NULL COMMENT 'Номер объекта',
  `store` int(5) NOT NULL COMMENT 'Номер объекта',
  `code` varchar(255) NOT NULL COMMENT 'Код товара или штрихкод',
  `code_1c` varchar(255) DEFAULT NULL COMMENT 'Код товара в 1Сэ',
  `name` varchar(255) NOT NULL COMMENT 'Имя объекта',
  `price` varchar(255) DEFAULT NULL COMMENT 'Цена',
  `price1` varchar(255) DEFAULT NULL COMMENT 'Цена 1',
  `price2` varchar(255) DEFAULT NULL COMMENT 'Цена 2',
  `price3` varchar(255) DEFAULT NULL COMMENT 'Цена 3',
  `price4` varchar(255) DEFAULT NULL COMMENT 'Цена 4',
  `avail` int(3) NOT NULL COMMENT 'Доступность',
  `quantity` float DEFAULT NULL COMMENT 'Количество',
  `quantity_min` float DEFAULT NULL COMMENT 'Минимальное количество хранения',
  `quantity_max` float DEFAULT NULL COMMENT 'Максимальное количество хранения',
  `date` datetime NOT NULL COMMENT 'Время изменения',
  PRIMARY KEY (`id`),
  UNIQUE KEY `ustore` (`item_id`,`store`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='Склад'
Команда «вставить или обновить» теперь выглядит так:
Код:
INSERT INTO `store` (
`store`.`price`,
`store`.`price1`,
`store`.`price2`,
`store`.`price3`,
`store`.`price4`,
`store`.`code_1c`,
`store`.`quantity`,
`store`.`name`,
`store`.`store`
)
SELECT
`import_items`.`price` AS price,
`import_items`.`price1` AS price1,
`import_items`.`price2` AS price2,
`import_items`.`price3` AS price3,
`import_items`.`price4` AS price4,
`import_items`.`item_id_1c` AS code_1c,
`import_items`.`quantity` AS quantity,
`import_items`.`name` AS name,
'1' AS store
FROM `import_items`
ON DUPLICATE KEY UPDATE
`store`.`price`=`import_items`.`price`,
`store`.`price1`=`import_items`.`price1`,
`store`.`price2`=`import_items`.`price2`,
`store`.`price3`=`import_items`.`price3`,
`store`.`price4`=`import_items`.`price4`,
`store`.`code_1c`=`import_items`.`item_id_1c`,
`store`.`quantity`=`import_items`.`quantity`,
`store`.`name`=`import_items`.`name`,
`store`.`store`='1'
;
Вставляет только 1 строку, хотя в БД более 1200.
Почему только одну? Это какая-то особенность MySQL или?
 

starwanderer

Хранитель порядка
Команда форума
Модератор
Регистрация
20 Ноя 2016
Сообщения
1.571
Реакции
3.249
Для начала: item_id не увидел в INSERT. Оно входит в уникальный индекс. А также полей code, avail, date. Они все NOT NULL, а дефолтных значений не задано.

Предложение:
Поэкспериментируйте с сокращенными таблицами.
Оставте во временной и складской поля: id, item_id, store, ну и какое-нибудь дополнительное, к примеру, price.
Отработайте нужную вам логику, а потом просто добавте остальные поля.

Конструкция ON DUPLICATE KEY UPDATE Для просмотра ссылки Войди или Зарегистрируйся к значительному увеличению счетчика.

Ну и ещё, как вариант, можно разбить на два запроса (с соответствующими подзапросами )
1. UPDATE по совпадающим ключам
2. INSERT по отсутствующим, в принимающей таблице, что скорее всего, значительно меньше займёт времени.
Конечно, при условии, что во временную таблицу в это время ничего не будет добавляться.
 
Последнее редактирование:

Den1xxx

Постоялец
Регистрация
15 Янв 2014
Сообщения
289
Реакции
161
Решил задачу.
Переделал всё по-другому.
Вот план, который реализовал и работает, может кому пригодится ещё.
1. Разбил склады с одной таблицы на отдельные `store`→`store_1`,`store_2`,`store_3` и т.д.
2. Создание, редактирование и удаление нового склада.
Далее $store — таблица склада
2.1 При создании «склада» импортируем объекты из «базовой» таблицы `items` (объекты)
Код:
"
    CREATE TABLE `store_{$store}`
    SELECT *
    FROM `items`
    ";
2.2 Редактирование. Это собственно то, что не получалось.
Сначала — импорт во временную таблицу `import_items` Этот процесс опустим, он сложен.
Делается множеством запросов и кодом на PHP. Как придумать лучше, пока не знаю, но пока работает.
Потом 1 запросом вставляем в cоответствующий склад:
Код:
"
UPDATE
    `{$table}`,`import_items`
     SET 
   `{$table}`.`price` = `import_items`.`price`,
   `{$table}`.`price1` = `import_items`.`price1`,
   `{$table}`.`price2` = `import_items`.`price2`,
   `{$table}`.`price3` = `import_items`.`price3`,
   `{$table}`.`price4` = `import_items`.`price4`,
   `{$table}`.`code_1c` = `import_items`.`item_id_1c`,
   `{$table}`.`quantity` = `import_items`.`quantity`,
   `{$table}`.`name` = `import_items`.`name`
     WHERE
   `{$table}`.`id` = `import_items`.`item_id`;
"
2.3 Удаление
Код:
"DROP TABLE IF EXISTS `store_{$store}`"
3. Остальное (не сделано).
Осталось еще продумать редактирование таблицы `items` (объекты)
При добавлении объекта, редактировании и удалении нужно также производить изменения в складах тоже. Доделать права пользователей — будет новая роль «Зав. складом». Они смогут редактировать количества и цены товаров. Возможно, что-то ещё.
Также осталось сделать логику отображения товара по складам на сайте.
Думаю, так: если пользователь выбрал склад отображения — выборку делаем из $store вместо `items`
Там что там все просто.
Спасибо всем, кто откликнулся.
 
Сверху