MySQL - UPDATE or INSERT if exists - mysql

I have a table in a MySQL database that needs to be updated if an instance does not already exist. I have tried the following methods but are no closer to a solution:
SET #last_message_id = (
SELECT id FROM mailbox_last_message WHERE conversationId = '13'
);
BEGIN TRANSACTION;
UPDATE mailbox_last_message SET conversationId = '13', initiatorMessageId = '20', interlocutorMessageId = '10'
WHERE id = #last_message_id
IF (##ROWCOUNT = 0)
INSERT INTO mailbox_last_message ( id , conversationId , initiatorMessageId , interlocutorMessageId )
VALUES ('' , '13', '20', '0' );
COMMIT;
And this one:
SET #last_message_id = (
SELECT `id` FROM mailbox_last_message WHERE `conversationId` = 13);
INSERT INTO mailbox_last_message ( id , conversationId , initiatorMessageId , interlocutorMessageId )
VALUES ( '', '13', '20', '0' ) ON DUPLICATE
KEY UPDATE id = #last_message_id
This solution creates a new instance with conversationId 13 which is not what I want. I've tried to search the documentation and various tutorials/examples online but I can't find any suitable solution. Any help will be greatly appreciated.

If you have a unique index on the fields that you want to keep unique, you can use INSERT IGNORE INTO syntax
SET #last_message_id = (
SELECT id FROM mailbox_last_message WHERE conversationId = '13'
);
INSERT IGNORE INTO mailbox_last_message ( id , conversationId , initiatorMessageId , interlocutorMessageId )
VALUES ('' , '13', '20', '0' ) ON DUPLICATE KEY UPDATE id = #last_message_id;

Related

mysql multiple values () include, need update based on condition

I need to update the fields on duplicate key if one columns value is equal to soemthing. Right now I have something like this:
INSERT INTO `table` (metric,amount,something1,something2)
VALUES (metric,amount,something1,something2),
(metric,amount,something1,something2),
(metric,amount,something1,something2)
ON DUPLICATE KEY UPDATE
amount = IF (metric = '6', amount = amount + ( '"+amount+"'),'')
ELSEIF (metric = '8' , amount = amount + ( '"+impressions+"') ,'')
ELSEIF (metrtic = '11' , amount = amount + ( '"+impressions+"') ,'');
What am I doing wrong here?
If I understand correctly, you can use UPDATE , self JOIN With CASE WHEN
[DUPLICATE KEY] can fill you want to check DUPLICATE column.
UPDATE `table` r
JOIN (
SELECT Count(*) cnt,[DUPLICATE KEY]
from `table`
group by [DUPLICATE KEY]
) t1 on r.[DUPLICATE KEY] = t1.[DUPLICATE KEY] and t1.cnt > 1
SET r.amount = (CASE WHEN r.metric = '6' THEN r.amount+ ( '"+amount+"'),''
WHEN r.metric = '8' THEN r.amount + ( '"+impressions+"') ,''
WHEN r.metric = '11' THEN r.amount+ ( '"+impressions+"') ,''
ELSE r.amount
END)
What eventually worked for me is:
INSERT INTO `table` (metric,amount,something1,something2)
VALUES (metric,amount,something1,something2),
(metric,amount,something1,something2),
(metric,amount,something1,something2)
ON DUPLICATE KEY UPDATE
metric = VALUES(metric),
amount = amount + VALUES (amount),
modified = NOW(),
something1= VALUES(something1);
Hope this helps anyone in the future.

Complex insert query with insert into and where subquery in Laravel

I am trying to figure out the best way to code this using Query Builder or Eloquent.
In it's simplest form it should prevent insert of a new buy request if an item already in transactions table. I haven't found any useful reference other than running a complete raw query.
INSERT INTO `transactions`
(`user_id`, `item_id`, `type`, `created_at`, `updated_at`)
SELECT
1, 186808, 'bought', NOW(), NOW()
WHERE
(
SELECT
SUM(
CASE
WHEN `type` = 'bought' THEN 1
WHEN `type` = 'sold' THEN -1
END
)
FROM `transactions`
WHERE
(`item_id`, `user_id`) = (186808, 1)
GROUP BY `item_id`
) = 0
In Laravel, you can use DB::raw(<your_complex_query_here>) to achieve this.
DB::raw("INSERT INTO `transactions`
(`user_id`, `item_id`, `type`, `created_at`, `updated_at`)
SELECT
1, 186808, 'bought', NOW(), NOW()
WHERE
(
SELECT
SUM(
CASE
WHEN `type` = 'bought' THEN 1
WHEN `type` = 'sold' THEN -1
END
)
FROM `transactions`
WHERE
(`item_id`, `user_id`) = (186808, 1)
GROUP BY `item_id`
) = 0");
For more, refer to Laravel docs here https://laravel.com/docs/5.7/queries#raw-expressions

update sql with case and update the value whichever case is right

UPDATE users SET log = CASE WHEN id = 2 THEN 1 ELSE 0 END WHERE r_id = 1
This updates timestamp of 2 rows one which is previous log=1 and the current log=1 .How can I update only the current log=1 ?
The table:
CREATE TABLE `users` (
`sno` int(255) NOT NULL AUTO_INCREMENT,
`id` varchar(255) NOT NULL,
`r_id` varchar(255) NOT NULL,
`log` int(11) NOT NULL,
`last_login` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`sno`)
)
INSERT INTO `users` (`sno`, `id`, `r_id`, `log`, `last_login`) VALUES
(1, '1', '1', 0, '2014-05-13 14:44:09'),
(2, '2', '1', 0, '2014-05-13 14:45:07'),
(3, '3', '1', 0, '2014-05-13 14:44:09'),
(4, '4', '1', 0, '2014-05-13 14:44:09'),
(5, '5', '1', 0, '2014-05-13 15:19:23'),
(6, '6', '2', 1, '0000-00-00 00:00:00'),
(7, '7', '3', 1, '0000-00-00 00:00:00');
Answer :
UPDATE users SET log = CASE WHEN id = 2 THEN 1 ELSE 0 END,last_login = CASE WHEN id = 2 THEN now() ELSE last_login END WHERE r_id = 1
You seem to have two conditions in the case but only one then. The following is speculation on what you want:
UPDATE users
SET log = (CASE WHEN id = '2' AND last_login = now() THEN 1
ELSE 0
END)
WHERE r_id = '1';
Do note that comparing a value such as last_login to now() is very dangerous. You will likely never get a match. Perhaps something like:
UPDATE users
SET log = (CASE WHEN id = '2' AND
last_login >= now() - interval 1 second
THEN 1
ELSE 0
END)
WHERE r_id = '1';
EDIT:
If you want to update only the last row in users meeting these conditions, perhaps you want:
UPDATE users
SET log = (CASE WHEN id = '2' THEN 1 ELSE 0 END)
WHERE r_id = '1'
ORDER BY last_login DESC
LIMIT 1;
NOW() is a function and should not be in quotes:
UPDATE users SET log = CASE WHEN id = '2' THEN 1 AND last_login = NOW() ELSE 0 END WHERE r_id = '1'
By being in quotes you are telling MySQL the value is the literal string "now()" instead of the function.

list of several names, to update their rows in the table with same information

Can somebody refresh my memory on how to build a query for this.
I want to use a list of several names (first and last), to update their rows in the table with same information. for example:
if I have a table set up with the columns:
[first_name],[last_name],[dob],[married_status]
I want to find:
(bob, smith),
(robert, john),
(jane, doe);
and edit their field for [married_status] to 'm'.
how do I structure this search and replace?
Thanks!
Use the IN operator:
UPDATE myTable
SET married_status = 'm'
WHERE (first_name, last_name) IN (
('bob' , 'smith'),
('robert', 'john'),
('jane' , 'doe'))
Code:
UPDATE tablename
SET married_status = 'm'
WHERE
( first_name = 'bob' AND last_name = 'smith' )
OR
( first_name = 'robert' AND last_name = 'john' )
OR
( first_name = 'jane' AND last_name = 'doe' )
You would use UPDATE query:
UPDATE `table`
SET `married_status` = 'm'
WHERE
(`first_name` = 'bob' AND `last_name` = 'smith')
OR (`first_name` = 'robert' AND `last_name` = 'john')
OR (`first_name` = 'jane' AND `last_name` = 'doe')

Topological sorting in sql

I am resolving dependency between some objects in a table.
I have to do something with objects in order their dependency.
For example, the first object doesn't depend on any object. The second and third ones depends on first one and so on. I have to use topological sorting.
Could someone show the sample of implementation so sorting in t-sql.
I have a table:
create table dependency
(
DependencyId PK
,ObjectId
,ObjectName
,DependsOnObjectId
)
I want to get
ObjectId
ObjectName
SortOrder
Thank you.
It seams, it works:
declare #step_no int
declare #dependency table
(
DependencyId int
,ObjectId int
,ObjectName varchar(100)
,DependsOnObjectId int
,[rank] int NULL
,degree int NULL
);
insert into #dependency values (5, 5, 'Obj 5', 2, NULL, NULL)
insert into #dependency values (6, 6, 'Obj 6', 7, NULL, NULL)
insert into #dependency values (2, 2, 'Obj 2', 1, NULL, NULL)
insert into #dependency values (3, 3, 'Obj 3', 1, NULL, NULL)
insert into #dependency values (1, 1, 'Obj 1', 1, NULL, NULL)
insert into #dependency values (4, 4, 'Obj 4', 2, NULL, NULL)
insert into #dependency values (7, 7, 'Obj 7', 2, NULL, NULL)
update #dependency set rank = 0
-- computing the degree of the nodes
update d set d.degree =
(
select count(*) from #dependency t
where t.DependsOnObjectId = d.ObjectId
and t.ObjectId <> t.DependsOnObjectId
)
from #dependency d
set #step_no = 1
while 1 = 1
begin
update #dependency set rank = #step_no where degree = 0
if (##rowcount = 0) break
update #dependency set degree = NULL where rank = #step_no
update d set degree = (
select count(*) from #dependency t
where t.DependsOnObjectId = d.ObjectId and t.ObjectId != t.DependsOnObjectId
and t.ObjectId in (select tt.ObjectId from #dependency tt where tt.rank = 0))
from #dependency d
where d.degree is not null
set #step_no = #step_no + 1
end
select * from #dependency order by rank
You have a simple tree structure with only one path to each ObjectId so labeling based off number of DependsOnObjectId links traversed gives only one answer and a good enough answer to process the right stuff first. This is easy to do with a common table expression and has the benefit of easy portability:
with dependency_levels as
(
select ObjectId, ObjectName, 0 as links_traversed
from dependency where DependsOnObjectId is null
union all
select ObjectId, ObjectName, links_traversed+1
from dependecy
join dependency_levels on dependency.DependsOnObjectId = dependency_levels.ObjectId
)
select ObjectId, ObjectName, links_traversed
from dependency_levels
order by links_traversed