简体   繁体   中英

MySQL conditional insert with insert .. select

I have an ecommerce site wherby customers login and see prices for various products. Each customer has their own pricelist and the the prices can be set a number of ways (sources). The table is below:

CREATE TABLE customer_price_list (
  customer_price_id int(11) NOT NULL AUTO_INCREMENT,
  customer_account_id int(11) NOT NULL,
  product_id int(11) DEFAULT NULL,
  currency_id int(11) DEFAULT NULL,
  customer_price decimal(7,2) DEFAULT NULL,
  source enum('TRADE_DEFAULT','TEMPLATE','SAGE','MANUAL') DEFAULT NULL,
  PRIMARY KEY (customer_price_id),
  KEY customer_account_id (customer_account_id),
  KEY product_id (product_id),
  KEY currency_id (currency_id),
  KEY source (source)
) 

Taking just the product_id, customer_price and source, sample data for one customer may look like (using a string for product_id just for illustration) :

Prod_1, 10.00, TRADE_DEFAULT 
Prod_2, 20.00, TRADE_DEFAULT 
Prod_3, 25.00, MANUAL 

And a different customer:

Prod_1, 7.50, SAGE 
Prod_2, 20.00, TRADE_DEFAULT 
Prod_3, 30.00, TRADE_DEFAULT 

The basic price for something, without a discount, is when the source is TRADE_DEFAULT - the above shows these two customers had the TRADE_DEFAULT price for two items each but got a discount on one item.

The TRADE_DEFAULT prices are set by importing a CSV file which has product_id, currency_id and customer_price in it. Within PHP I loop through all the rows in the CSV and bind the values to this query:

insert into customer_price_list  
(customer_price_id, customer_account_id, product_id, currency_id, customer_price, source) 
select 0, customer_account_id, :product_id, :currency_id, :price, 'TRADE_DEFAULT' from customer_account

This works fine when customer_price_list is empty (for all product_id/currency_id combinations within the CSV). But, if some customers already have product_id/currency_id entries this will result in extra rows (ie there will be two or more prices for a product for that customer)

So, when processing the CSV I want to:

A) update any existing TRADE_DEFAULT to the new value from the CSV (again run from a loop of the CSV contents)

update  customer_price_list set customer_price = :price
        where currency_id=:currency_id and product_id=:product_id and source ='TRADE_DEFAULT'

B) insert a TRADE_DEFAULT price if that customer has no price for that product/currency

insert (ONLY IF NO PRICE OF ANY SOURCE IS THERE) into customer_price_list  
(customer_price_id, customer_account_id, product_id, currency_id, customer_price, source) 
select 0, customer_account_id, :product_id, :currency_id, :price, 'TRADE_DEFAULT' from customer_account

This is where I need help. I have searched for conditional insert queries but I can only find where they are inserting one recoord like this:

insert into table1 (user,rating,last_modified)
select 'user1', 1999, NOW() from table1
where not exists (
select * from table1
where last_modified > '2007-04-13 08:52:41'
and user='user1'
) limit 1

But I am wanting to do insert .. select and do an inseret, if needed, for all customers.

Thanks.

Try using merge:

https://docs.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql

It may be helpful with your case as it allows to insert values based on condition and update if they already exist.

Using @Stavr00 suggestion I came up with this:

First add an index across three columns to make product/currency unique for each customer:

alter table customer_price_list add  UNIQUE INDEX unq_cust_prod (customer_account_id ASC, product_id ASC, currency_id ASC)

Then change the query:

insert into customer_price_list  
(customer_price_id, customer_account_id, product_id, currency_id, customer_price, source) 
select 0, customer_account_id, :product_id, :currency_id, :price, 'TRADE_DEFAULT' from customer_account
ON DUPLICATE KEY UPDATE customer_price=customer_price;

By making the update set the price to the current value, the query becomes just the conditional insert. When combined with the update query in step A in my question, it does what I want.

I guess I could have used the ON DUPLICATE KEY UPDATE to do the work of the other query and do it all on one. But, I would only want to update existing records of source = TRADE_DEFAULT so not sure how to do that.

Also, it seems I could have used insert ignore, but as this would not flag some real errors like type mismatch, I thought my solution was safer.

Comments welcome!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM