MySQL select and then insert or update if exists - mysql

I need to find multiple rows related to users and then insert into another table or update if record exists for current day.
I am doing this way
SELECT CASE WHEN
(
SELECT
DISTINCT `userid`,
COUNT(DISTINCT `userip`,`userid`) AS `count`,
#date:=UNIX_TIMESTAMP(CURDATE())
FROM `tablename`
WHERE (`date` >= UNIX_TIMESTAMP(CURDATE())) GROUP BY `userid`
)
THEN
(
UPDATE `tablename2` SET `count`=`count`,`userid`=`userid`,`date`=`date` WHERE `date` >= UNIX_TIMESTAMP(CURDATE()))
)
ELSE
(
INSERT INTO `tablename2` (`count`,`userid`,`date`) VALUES(`count`,`userid`,`date`);
)
END
But this is giving me syntax error near UPDATE..
How can I fix this?

I am guessing that you want one row per user and date in tablename2. If so, enforce this rule with a unique index:
CREATE UNIQUE INDEX idx_tablename2(userid, date)
Then the database enforces it.
Your SQL is a mess, but I think I can see what you are trying to do. The basic idea is INSERT . . . ON DUPLICATE KEY UPDATE. I think the following does what you want:
INSERT INTO `tablename2` (`count`, `userid`, `date`)
SELECT `userid`, COUNT(DISTINCT `userip`, `userid`) AS `count`,
UNIX_TIMESTAMP(CURDATE())
FROM `tablename`
WHERE `date` >= UNIX_TIMESTAMP(CURDATE())
GROUP BY `userid`
ON DUPLICATE KEY UPDATE `count` = VALUES(`count`);

Related

Keep the latest 7 records and delete all other query issue

I have a mysql table
CREATE TABLE IF NOT EXISTS `mytable` (
`i_contact_id` int(16) NOT NULL AUTO_INCREMENT,
`s_contact_name` char(48) NOT NULL,
`ts_contact_scraped` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Date Time when contact is last scraped.',
PRIMARY KEY (`i_contact_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
INSERT INTO `mytable` (`i_contact_id`, `s_contact_name`, `ts_contact_scraped`) VALUES
(1, 'aaaa', '2018-07-27 02:30:30'),
(2, 'bbbb', '2017-03-28 04:13:08'),
(3, 'cccc', '2017-03-12 03:52:57'),
(4, 'dddd', '2017-04-18 07:13:34'),
(5, 'eeee', '2018-05-29 15:22:23'),
(6, 'ffff', '2018-02-23 13:27:24'),
(7, 'gggg', '2016-10-17 22:50:24'),
(8, 'hhhh', '2018-07-20 14:02:14'),
(9, 'iiii', '2020-03-24 10:56:02');
I want to keep 7 latest rows and delete all oldest rows based on ts_contact_scraped field but it don't work properly.
Here is my delete query
DELETE FROM `mytable`
WHERE i_contact_id <= (
SELECT i_contact_id
FROM (
SELECT i_contact_id
FROM `mytable`
ORDER BY ts_contact_scraped DESC
LIMIT 1 OFFSET 7
) foo
)
My original table has more than 1100000 rows, I want to run above query periodically using PHP to purge oldest rows, there is some other logic involved so I want to delete the oldest rows based on ts_contact_scraped field.
When I run this query on my original table it deletes more than expected rows.
Here is fiddle
http://sqlfiddle.com/#!9/9414e2/1/0
You can use JOIN:
DELETE t
FROM `mytable` t JOIN
(SELECT i_contact_id
FROM `mytable`
ORDER BY ts_contact_scraped DESC
LIMIT 1 OFFSET 7
) tt
ON tt.i_contact_id = t.i_contact_id
In your delete statement you are relying on a higher ts_contact_scraped also meaning a higher i_contact_id. At least in your example this is not given.
So stick to ts_contact_scraped instead:
DELETE FROM `mytable`
WHERE ts_contact_scraped <= (
SELECT ts_contact_scraped
FROM (
SELECT ts_contact_scraped
FROM `mytable`
ORDER BY ts_contact_scraped DESC
LIMIT 1 OFFSET 7
) foo
);
Here is your altered fiddle: http://sqlfiddle.com/#!9/610cb4/1
(If there can be duplicate ts_contact_scraped, though, things will get more complicated.)
DELETE t1.*
FROM `mytable` t1
LEFT JOIN ( SELECT i_contact_id
FROM `mytable`
ORDER BY ts_contact_scraped DESC
LIMIT 7 ) t2 ON t1.i_contact_id = t2.i_contact_id
WHERE t2.i_contact_id IS NULL;
fiddle
or
DELETE t1.*
FROM `mytable` t1, ( SELECT ts_contact_scraped
FROM `mytable`
ORDER BY ts_contact_scraped DESC
LIMIT 1 OFFSET 7 ) t2
WHERE t1.ts_contact_scraped <= t2.ts_contact_scraped;
fiddle

MySQL INSERT multiple rows if certain values don't exist

I have the following query which works correctly:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT 10, 'user_other_unit_moved', now(), 8383
FROM Events
WHERE NOT EXISTS (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
LIMIT 1;
What the query does is check to see if a row exists in my Events table that matches the event type and unit ID I wish to INSERT. If it finds an existing record, it does not proceed with the INSERT. However, if it does not find a record then it proceeds with the INSERT.
This is the structure of my Events table:
CREATE TABLE `Events` (
`event_ID` int(11) NOT NULL,
`user_ID` int(11) NOT NULL,
`event_type` varchar(35) NOT NULL,
`event_creation_datetime` datetime NOT NULL,
`unit_ID` int(10) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `Events`
ADD PRIMARY KEY (`event_ID`),
ADD KEY `unit_ID` (`unit_ID`);
ALTER TABLE `Events`
MODIFY `event_ID` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
The problem I have is trying to get the above query to work correctly when trying to INSERT multiple rows. I know how to INSERT multiple rows using comma delimited VALUES, but no matter what I try I get syntax errors. Here is the query I have been playing with:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
VALUES (
(SELECT 10, 'user_other_unit_moved', now(), 8383
FROM Events
WHERE NOT EXISTS (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
LIMIT 1)),
(SELECT 10, 'user_other_unit_moved', now(), 8380
FROM Events
WHERE NOT EXISTS (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8380)
LIMIT 1))
);
However, no matter what I try (inserting, removing parentheses etc.) I get either the generic "You have an error in your SQL syntax;" or "Operand should contain only 1 column".
I have also tried this alternative based on other StackOverflow posts:
INSERT IGNORE INTO Events (event_ID, user_ID, event_type, event_creation_datetime, unit_ID)
VALUES
(SELECT (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383), 10, 'user_other_unit_moved', now(), 8383),
(SELECT (SELECT event_ID FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383), 10, 'user_other_unit_moved', now(), 8383);
But this fails with "Can't specify target table for update in FROM clause" even if I try to return results using temporary tables.
Is it just an error with my syntax, or am I trying to do something not possible with the way my query is laid out? And if it's just an error, how would I write the query so that it works as I've intended? Note that I do not want to use multi-queries - I want the query to work as one statement.
Thanks,
Arj
Don't use VALUES, just INSERT ... SELECT and not FROM events.
Then UNION ALL.
This code works for MySql 5.6:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT *
FROM (
SELECT 10 user_ID, 'user_other_unit_moved' event_type,
now() event_creation_datetime, 8383 unit_ID
UNION ALL
SELECT 10, 'user_other_unit_moved', now(), 8380
) t
WHERE NOT EXISTS (
SELECT 1 FROM Events e
WHERE e.event_type = t.event_type AND e.unit_ID = t.unit_ID
);
See the demo.
This code works for MySql 5.7+:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT * FROM (
SELECT 10, 'user_other_unit_moved', now(), 8383
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
UNION ALL
SELECT 10, 'user_other_unit_moved', now(), 8380
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8380)
) t
See the demo
And this for MySql 8.0+:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT 10, 'user_other_unit_moved', now(), 8383
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8383)
UNION ALL
SELECT 10, 'user_other_unit_moved', now(), 8380
WHERE NOT EXISTS (SELECT 1 FROM Events WHERE event_type = 'user_other_unit_moved' AND unit_ID = 8380);
See the demo.
Although you can write this with just union all:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
SELECT x.user_id, x.event_type, now(), x.unit_id
FROM (SELECT 10 as user_id, 8383 as unit_id, 'user_other_unit_moved' as event_type
) x
WHERE NOT EXISTS (SELECT 1 FROM Events e2 WHERE e2.event_type = x.event_type AND e2.unit_ID = x.unit_ID)
UNION ALL
SELECT x.user_id, x.event_type, now(), x.unit_id
FROM (SELECT 10 as user_id, 8380 as unit_id, 'user_other_unit_moved' as event_type
) x
WHERE NOT EXISTS (SELECT 1 FROM Events e2 WHERE e2.event_type = x.event_type AND e2.unit_ID = x.unit_ID);
I suspect there is a better way. If a unit_id can have only one row for each event type, then you should specify that using a unique constraint or index:
create unique constraint unq_events_unit_id_event_type on events(unit_id, event_type);
It is better to have the database ensure integrity. In particularly, your version is subject to race conditions. And to duplicates being inserted within the same statement.
Then you can use on duplicate key to prevent duplicate rows:
INSERT INTO Events (user_ID, event_type, event_creation_datetime, unit_ID)
VALUES (10, 'user_other_unit_moved', now(), 8383),
(10, 'user_other_unit_moved', now(), 8380)
ON DUPLICATE KEY UPDATE unit_ID = VALUES(unit_ID);
The update actually does nothing (because unit_ID already has that value). But it does prevent an error and a duplicate row from being inserted.

MYSQL INSERT INTO WITH SELECT not working?

i am trying to do a insert into a with SELECT, bit this following query doesnt seems to be working for some reason,
INSERT INTO `employer_data`
(`employer_id`, `data`, `datetime`)
VALUES
( SELECT employer_id, employer_id AS data, NOW() AS `datetime` FROM employer );
Any ideas ?
remove values keyword
INSERT INTO `employer_data`
(`employer_id`, `data`, `datetime`)
( SELECT employer_id, employer_id AS data, NOW() AS `datetime` FROM employer );
Syntax was wrong.
Try:
INSERT INTO `employer_data`
(`employer_id`, `data`, `datetime`)
SELECT employer_id, employer_id AS data, NOW() AS `datetime` FROM employer;
Refer To:
MySQL: INSERT ... SELECT Syntax

insert data from one table to another in mysql

i want to read all data from one table and insert some data in to another table. my query is
INSERT INTO mt_magazine_subscription (
magazine_subscription_id,
subscription_name,
magazine_id,
status )
VALUES (
(SELECT magazine_subscription_id,
subscription_name,
magazine_id
FROM tbl_magazine_subscription
ORDER BY magazine_subscription_id ASC), '1')
but i got an error that
#1136 - Column count doesn't match value count at row 1
please help me.
You can use INSERT...SELECT syntax. Note that you can quote '1' directly in the SELECT part.
INSERT INTO mt_magazine_subscription (
magazine_subscription_id,
subscription_name,
magazine_id,
status )
SELECT magazine_subscription_id,
subscription_name,
magazine_id,
'1'
FROM tbl_magazine_subscription
ORDER BY magazine_subscription_id ASC
If you want insert all data from one table to another table there is a very simply sql
INSERT INTO destinationTable (SELECT * FROM sourceDbName.SourceTableName);
It wont work like this.
When you try to insert the row using a query all values should be there in query.
With the above problem you want to insert
magazine_subscription_id, subscription_name, magazine_id, status
in select query you have
magazine_subscription_id, subscription_name, magazine_id, status 1 it is not possible.
If you want to insert either you need to insert using query of direct values
Actually the mysql query for copy data from one table to another is
Insert into table2_name (column_names) select column_name from table1
where, the values copied from table1 to table2
If there is a primary key like "id" you have to exclude it for example my php table has: id, col2,col3,col4 columns. id is primary key so if I run this code:
INSERT INTO php (SELECT * FROM php2);
I probably get this error:
#1062 - Duplicate entry '1' for key 'PRIMARY'
So here is the solution, I excluded "id" key:
INSERT INTO php ( col2,col3,col4) (SELECT col2,col3,col4 FROM php2);
So my new php table has all php2 table rows anymore.
INSERT INTO mt_magazine_subscription (
magazine_subscription_id,
subscription_name,
magazine_id,
status )
VALUES (
(SELECT magazine_subscription_id,
subscription_name,
magazine_id,'1' as status
FROM tbl_magazine_subscription
ORDER BY magazine_subscription_id ASC));
Insert data from one table to other with condition in MySQL and same will work in SQL Server as well. Only non existing data will get updated. Both table have same structure so column need not to pass.
insert into table_A
select * from table_A_copy
where not exists
(
select * from table_A where table_A_copy.clm_a=table_A.clm_a and table_A_copy.clm_b=table_A.clm_b and table_A_copy.clm_c=table_A.clm_c
);
Try this. Your doing in wrong way.
INSERT INTO mt_magazine_subscription(
magazine_subscription_id,
subscription_name,
magazine_id, status) VALUES (
(SELECT magazine_subscription_id, subscription_name,
magazine_id,1 as status FROM tbl_magazine_subscription
ORDER BY magazine_subscription_id ASC)
)
INSERT INTO mt_magazine_subscription (
magazine_subscription_id,
subscription_name,
magazine_id,
status )
VALUES (
(SELECT magazine_subscription_id,
subscription_name,
magazine_id,'1' as status
FROM tbl_magazine_subscription
ORDER BY magazine_subscription_id ASC))
Try to use this
INSERT INTO mt_magazine_subscription (
magazine_subscription_id,
subscription_name,
magazine_id,
status )
SELECT magazine_subscription_id,
subscription_name,
magazine_id,
'1'
FROM tbl_magazine_subscription
ORDER BY magazine_subscription_id ;
Use the hard coded value in select clause
INSERT INTO destination_table (
Field_1,
Field_2,
Field_3)
SELECT Field_1,
Field_2,
Field_3
FROM source_table;
BUT this is a BAD MYSQL
Do this instead:
drop the destination table: DROP DESTINATION_TABLE;
CREATE TABLE DESTINATION_TABLE AS (SELECT * FROM SOURCE_TABLE);
INSERT INTO mt_magazine_subscription SELECT *
FROM tbl_magazine_subscription
ORDER BY magazine_subscription_id ASC

Every derived table must have its own alias - error from combination descending MySQL

I want to order one mysql table by two strtotime timestamps from two different columns. I've got the following mysql command:
SELECT * FROM (
(SELECT '1' AS `table`, `vid_req_timestamp` AS `timestamp`, `title` FROM `movies` WHERE `vid_req` = '1')
UNION
(SELECT '2' AS `table`, `ost_req_timestamp` AS `timestamp`, `title` FROM `movies` WHERE `ost_req` = '1')
)
ORDER BY `timestamp` DESC
This gives me an error:
#1248 - Every derived table must have its own alias
I want to combine vid_req_timestamp and ost_req_timestamp and make those descending. And it's important to know where the timestamp came from (somehow).
In this case, the derived table that requires an alias is the one that you are SELECTing * from.
Indentation helps make that clearer.
SELECT * FROM
(
(SELECT '1' AS `table`, `vid_req_timestamp` AS `timestamp`, `title` FROM `movies` WHERE `vid_req` = '1')
UNION
(SELECT '2' AS `table`, `ost_req_timestamp` AS `timestamp`, `title` FROM `movies` WHERE `ost_req` = '1')
) AS `some_table_name_lol_this_is_an_alias`
ORDER BY `timestamp` DESC