Mysql: most efficient way to get the ID from an attempted insertion? - mysql

I'm inserting some_data (a unique key column), and then using the resulting user_id (the primary key auto-increment column) in a separate statement (not shown)
INSERT IGNORE INTO users (some_data) VALUES ('test');
SELECT LAST_INSERT_ID(); <--- I do stuff with this.
But, of course, if some_data already exists (happens very frequently), LAST_INSERT_ID() returns 0. What is the best way to get the user_id based on the unique key some_data, in this case? Of course I can do a separate WHERE query, but not sure that is the most efficient.

From http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
INSERT INTO users ( id, some_col ) VALUES (n,some_val)
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), some_col=some_val;
Not an ignore but might do the job?
Edit:
To be clear, this will update some_col with some_val and then set the LAST_INSERT_ID to return the id of the duplicate row.
It could just as well be this if you didn't want to update any data on the duplicate but just set the LAST_INSERT_ID() call to give you what you want:
INSERT INTO users ( user_name ) VALUES ( 'bobloblaw' )
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID( id );
Edit 2:
Use a proc to do the work and get back the id
DELIMITER $$
CREATE PROCEDURE insert_test( val1 varchar(10), val2 varchar(10) )
BEGIN
INSERT INTO test.test_table ( col1, col2 ) SELECT val1, val2 FROM ( select 1 ) as a
WHERE NOT EXISTS (
select 1 from test.test_table t where t.col1 = val1
);
SELECT id FROM test.test_table where col1 = val1;
END $$
DELIMITER ;

Related

Insert into if not exists not inserting

INSERT INTO my_table (field_1, field_2)
SELECT val_1, val_2
FROM my_table
WHERE NOT EXISTS (SELECT field_1
FROM my_table
WHERE field_2 = val_2)
LIMIT 1
I can not use unique index on field_2 field.
I'm trying to insert if not exists a tuple with field2 = val_2.
Without the "where" clause, this insert.
With the "where" clause EVEN WHEN EMPTY TABLE, it won't insert.
Any help on that?
I guess val_1 and val_2 are not columns of the table, right?
They are values that you want to insert in the table.
So drop:
FROM my_table
and use:
INSERT INTO my_table (field_1, field_2)
SELECT val_1, val_2
WHERE NOT EXISTS (
SELECT field_1
FROM my_table
WHERE field2 = val_2
)
Solution is that check if key exist:
INSERT INTO my_table (field_1, field_2) ON DUPLICATE KEY INSERT IGNORE.
this question maybe useful.
First create a unique index on the column or columns that you don't want duplicated. I cannot tell if it is on both or just field_2:
create unique index unq_my_table_field_2 on my_table(field_2);
Then ignore the error using on duplicate key update:
INSERT INTO my_table (field_1, field_2)
VALUES (val_1, val_2)
ON DUPLICATE KEY UPDATE field_2 = VALUES(val_2); -- this is a no-op, because the value is already the same
The fact the your code doesn't work on an empty table has nothing to do with the WHERE clause but with using from my_table in the from clause. If there are no rows, then the query returns . . . no rows. No surprise there that nothing gets inserted.

What will be the insert query depends on previous data in same table?

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 ;

MySql. UPDATE if value exists - else INSERT (for not primary and not unique value)

I have my_table with column1 column.
If there are rows with column1='old' I want to update those rows.
Else, I want to insert a new row.
Something like this:
IF(
(EXISTS(
SELECT * FROM my_table WHERE column1='old'
)),
(UPDATE my_table SET column1='new' WHERE column1='old'),
(INSERT INTO my_table (column1) VALUES ('new') )
)
I use MySql so I cannot use IF on the beginning of query.
column1 is not unique and not primary. So I cannot use ON DUPLICATE KEY UPDATE or REPLACE

How to MERGE records in MYSQL

I'm able to use MERGE statement in both Oracle and MSSQL. Right now I have to use MYSQL. Does MYSQL has similar statement to merge data.
Lets say I have two tables:
create table source
(
col1 bigint not null primary key auto_increment,
col2 varchar(100),
col3 varchar(50)
created datetime
)
create table destination
(
col1 bigint not null primary key auto_increment,
col2 varchar(100),
col3 varchar(50)
created datetime
)
Now I want move all data from "source" to "destination". If record already exists in "destination" by key I need update, otherwise I need insert.
In MSSQL I use the following MERGE statement, similar can be used in ORACLE:
MERGE destination AS TARGET
USING(SELECT * FROM source WHERE col2 like '%GDA%') AS SOURCE
ON
(TARGET.col1 = SOURCE.col1)
WHEN MATCHED THEN
UPDATE SET TARGET.col2 = SOURCE.col2,
TARGET.col3 = SOURCE.col3
WHEN NOT MATCHED THEN
INSERT INTO
(col2,col3,created)
VALUES
(
SOURCE.col2,
SOURCE.col3,
GETDATE()
)OUTPUT $action INTO $tableAction;
WITH mergeCounts AS
(
SELECT COUNT(*) cnt,
MergeAction
FROM #tableAction
GROUP BY MergeAction
)
SELECT #Inserted = (SELECT ISNULL(cnt,0) FROM mergeCounts WHERE MergeAction = 'INSERT'),
#Updated = (SELECT ISNULL(cnt,0) FROM mergeCounts WHERE MergeAction = 'UPDATE'),
#Deleted = (SELECT ISNULL(cnt,0) FROM mergeCounts WHERE MergeAction = 'DELETE')
so here I'm update records if exists and insert if new record. After MERGE statement I also able to count how many records was inserted, updated ...
Does it possible to have such implementation in MYSQL ??
Mysql has insert ... on duplicate key update ... syntax. use it like this:
insert into destination(col1, col2, col3, created)
select *
from source
on duplicate key update
col2 = values(col2),
col3 = values(col3),
created = values(created);
demo here
to get the number of affected rows, run select row_count() afterwards

update column with multiple values parsed from current column data

Hoping someone can help me with a mysql query
Here’s what I have:
I table with a column “networkname” that contains data like this:
“VLAN-338-Network1-A,VLAN-364-Network2-A,VLAN-988-Network3-A,VLAN-1051-Network4-A”
I need a MySQL query that will update that column with only the vlan numbers in ascending order, stripping out everything else. ie.
“338, 364, 988, 1051”
Thanks,
David
In this script, I create a procedure to loop through the networkname values and parse out the numbers to a separate table, and then update YourTable using a group_concat function. This assumes your networkname values follow the 'VLAN-XXX' pattern in your example where 'XXX' is the 3-4 digit number you want to extract. This also assumes each record has a unique ID.
CREATE PROCEDURE networkname_parser()
BEGIN
-- load test data
drop table if exists YourTable;
create table YourTable
(
ID int not null auto_increment,
networkname nvarchar(100),
primary key (ID)
);
insert into YourTable(networkname) values
('VLAN-338-Network1-A,VLAN-364-Network2-A,VLAN-988-Network3-A,VLAN-1051-Network4-A'),
('VLAN-231-Network1-A,VLAN-4567-Network2-A'),
('VLAN-9876-Network1-A,VLAN-321-Network2-A,VLAN-1678-Network3-A');
-- add commas to the end of networkname for parsing
update YourTable set networkname = concat(networkname,',');
-- parse networkname into related table
drop table if exists ParseYourString;
create table ParseYourString(ID int,NetworkNumbers int);
while (select count(*) from YourTable where networkname like 'VLAN-%') > 0
do
insert into ParseYourString
select ID,replace(substr(networkname,6,4),'-','')
from YourTable
where networkname like 'VLAN-%';
update YourTable
set networkname = right(networkname,char_length(networkname)-instr(networkname,','))
where networkname like 'VLAN-%';
end while;
-- update YourTable.networkname with NetworkNumbers
update YourTable t
inner join (select ID,group_concat(networknumbers order by networknumbers asc) as networknumbers
from ParseYourString
group by ID) n
on n.ID = t.ID
set t.networkname = n.networknumbers;
END//
Call to procedure and select the results:
call networkname_parser();
select * from YourTable;
SQL Fiddle: http://www.sqlfiddle.com/#!2/01c77/1