I'm trying to insert a new row with the same ID into a simple table but only want to insert if the values are different.
This table is to track price history of an item. The table has the following columns:
id, timestamp, productID, price
I only want to insert a new record if either the product doesn't exist or the product does exist but the price has changed.
Unfortunately I'm having a brain block due to my limited knowledge and would appreciate help in where to turn so I don't have any trials at the code to do this.
Thanks!
you can try something like this:
SET #PRODUCT = 1; # product id
SET #PRICE = 1; # new product price
insert into `t`(`product`, `timestamp`, `price`)
select v.product, now(), v.price
from
(select #PRODUCT as `product`, #PRICE as `price`) as v
left outer join
(select `product`, `price` from `t` where `product`=#PRODUCT order by `id` desc limit 1) as p
on (v.product=p.product)
where
(p.price is null) or
(p.price <> v.price);
so, this statement either insert new row (for new product or new price) or does nothing
u need composite primary key
ALTER TABLE products ADD PRIMARY KEY(product,price);
after this query if you insert if the product and price is same in your table returns error with duplicate entry
or it will insert the query even one field value changes
Related
I want to insert a row if it's one specific column value is not still available. If available, i want to update that row. Otherwise it will insert normally. What should be the SQL query for this task?
For example:
id, Product_id, user_id, quantity are the table's attributes
Considering,
[1, 450, 56, 2] is in table.
If i want to insert [2,450,56,3] then it will not create new row. It will update the previous row. Like [1,450,56,5].
I'd start by creating a unique constraint on the combination of product_id and user_id (or even a primary key if you don't have one on the table yet):
ALTER TABLE mytable
ADD CONSTRAINT uc_product_user UNIQUE (product_id, user_id);
And then you can use the on duplicate clause in an insert statement:
INSERT INTO mytable
VALUES (2, 450, 56, 3)
ON DUPLICATE KEY UPDATE quantity = quantity + VALUES(quantity);
You could set product_id and user_id as the primary key or unique key on the table and then use INSERT .. ON DUPLICATE KEY UPDATE. You can find more information about that here.
It would look something like:
INSERT INTO t1 (id, product_id, user_id, quantity) VALUES (2,450,56,3)
ON DUPLICATE KEY UPDATE quantity = quantity + 3;
Alternatively, you're going to have to write your own merge statement (MySql doesn't support merge, but you can fake it)
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_updateValue`(IN prm_productid INT, IN prm_userid INT, IN prm_quantity INT)
BEGIN
-- Check that the case actually exists first.
DECLARE vExists INT;
SELECT COUNT(1) INTO vExists FROM YourTable WHERE product_id = prm_orderid AND user_id = prm_userid;
IF vCaseExists = 1 THEN
UPDATE YourTable SET quantity = prm_quantity WHERE product_id = prm_orderid AND user_id = prm_userid;
ELSE
INSERT INTO YourTable (id, product_id, user_id, quantity) VALUES (2,450,56,3);
END IF;
END$$
DELIMITER ;
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 (i.e. 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://learn.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!
I've got the following table:
productId price
1 price_value1
2 price_value2
3 price_value3
I would like to insert a new product into the table and assign it a new productId. In this case its value equals to 4.
So I want my new table to look like so:
productId price
1 price_value1
2 price_value2
3 price_value3
4 price_value4
So as far as I understand, in order to do that I have to somehow retrieve the max value of productId and insert it using INSERT INTO mytable VALUES (productId + 1, price_value4).
But how do I find out the maximum value of productId?
I tried INSERT INTO mytable VALUES (SELECT MAX(productId) + 1 FROM mytable, price_value4) but it didn't work.
This should Work:
Select the max(productID) and price_value4 as a columns from mytable and insert the result.
INSERT INTO mytable (SELECT MAX(productId) + 1, 'price_value4' FROM mytable);
However, if you are not going to jump some number you can just add an auto increment id key to product_id and then you will have only to insert the price, the product ID will be incremented automatically..
This will do so :
ALTER TABLE mytable
MODIFY COLUMN `productId` INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT;
you can change INT(10) with the INT(5) for example depanding on the size you want to give to your productId column
EDIT :
In return to the OP question in comments why his solution wouldn't work
Some suggetions says you have to make the SELECT statment in insert always between parenthesis
INSERT INTO mytable VALUES ( (SELECT MAX(ID)+1 FROM mytable) , price_value4)
.. In my Case it Return
(1093): You can't specify target table
'mytable' for update in FROM clause
AND HERE IS WHY (Quoting From the documentation)
When selecting from and inserting into the same table, MySQL creates
an internal temporary table to hold the rows from the SELECT and then
inserts those rows into the target table. However, you cannot use
INSERT INTO t ... SELECT ... FROM t when t is a TEMPORARY table,
because TEMPORARY tables cannot be referred to twice in the same
statement
BUT there is away to overcome by using a query instead of the table itself in the FROM, which has the effect of copying the requested table values instead of referencing the one that you are updating..
INSERT INTO mytable VALUES (
(SELECT MAX(ID)+1 FROM (SELECT * FROM mytable ) as mytmp ),
'price_value4');
OR (Quoting From the documentation)
To avoid ambiguous column reference problems when the SELECT and the
INSERT refer to the same table, provide a unique alias for each table
used in the SELECT part, and qualify column names in that part with
the appropriate alias.
INSERT INTO mytable Values ( (SELECT MAX(ID)+1 FROM mytable as mytmp) , 'price_value4')
This is a duplicate question. In order to take advantage of the auto-incrementing capability of the column, do not supply a value for that column when inserting rows.
A simple syntax to create table
CREATE TABLE Product (
productId MEDIUMINT NOT NULL AUTO_INCREMENT,
price INT NOT NULL,
PRIMARY KEY (productid)
);
While inserting supplied default or leave column as blank or supplied value as NULL. Take a look at below code snippet.
INSERT INTO Product (price) VALUES
('10'),('20'),('4'),
('30');
refer this link
Inventory Table:
Inventory History Table:
The query:
INSERT INTO inventory_history (SKU, Quantity, timestamp)
SELECT SKU, Quantity, modifiedtime FROM inventory WHERE modifiedtime BETWEEN '2016-12-25 00:00:00' AND '2016-12-26 00:00:00';
The Trigger:
CREATE TRIGGER `sold_diff` BEFORE INSERT ON `inventory_history`
FOR EACH ROW begin
declare prev_quantity int(11) default 0;
declare prev_sku varchar(255) default null;
select sku
into prev_sku
from inventory_history
where prev_sku = NEW.sku
order by id desc
limit 1;
select quantity
into prev_quantity
from inventory_history
order by id desc
limit 1;
set NEW.sold = prev_quantity
;
end
The Result:
Now, how it's set-up is it's taking prev_quantity from the previous row, and putting it into the sold column.
I can not figure out a way to bind SKU in with prev_quantity, so that it will give me the previous Quantity value from the corresponding SKU.
Desired Result:
I've messed with a variety of different WHERE clauses on the two declared, but nothing is working right.. so I'm thinking this is not the right path to take.
How can this be achieved?
I think you are taking the wrong approach.
You seem to want an insert on the inventory table. When a new value is inserted or updated (or deleted), you then insert a row in the inventory_history table with the old and new values.
You then don't need an explicit insert on inventory_history.
My database structure is:
items (id, item_name)
user (id, username)
inventory(id, user_id FK, item_id FK, amount)
I have a select query which returns rows with (item_id, amount)
I just want to add values from that select query into that inventory table.
So what i need in pseudo code is:
FUNCTION give_items(IN in_user_id)
FOR EACH ROW FROM THAT SELECT:
IF ROW EXISTS with user_id = in_user_id AND item_id = SELECT.item_id THEN INSERT ROW
ELSE UPDATE ROW amount = amount + SELECT.amount
it is like INSERT INTO SELECT ... ON DUPLICATE KEY, but i need to respect user_id and item_id not PRIMARY KEY
#EDIT
This is what i got now:
INSERT INTO `items_inventory` (`user_id`,`item_id`,`amount`)
SELECT mu.user_id, mi.item_id, SUM(mu.amount*mi.income) as amount_sum
FROM `mining_machines_users` AS mu
LEFT JOIN `mining_machines_income` AS mi ON mu.machine_id=mi.machine_id
WHERE mu.user_id=in_user_id
GROUP BY mi.item_id
ON mu.user_id=in_user_id AND mi.item_id=VALUES(`item_id`) //NEED FIX
`amount`=`amount`+VALUES(`amount`)
Sorry for my bad English, i hope that you will help me :)
Is the id property necessary? otherwise its maybe easier if you make a combined primary key of user_id and item_id