Explain insert query with select queries inside - mysql

I'm refactoring someone's code where queries like this are all over the place and I can't understand what's going on. I have no idea what to search for and "mysql insert with nested select" doesn't yield anything helpful.
INSERT INTO stats_users_hour (
hour,
uid,
lastupdate,
hash1hr
)
SELECT * FROM (SELECT
? as hour,
? as uid,
? as lastupdate,
? as hash1hr) AS tmp
WHERE NOT EXISTS (
SELECT lastupdate FROM stats_users_hour WHERE lastupdate = ? AND uid = ?
) LIMIT 1
ON DUPLICATE KEY UPDATE lastupdate = ?, hash1hr = ?
I'm not even sure how to indent this properly. I'm assuming the first select uses the values yielded from the second select, but where does the second select get it's data from? Is this just an "update or create" query? And are the first select's results used as values for the insert query?
I'm sorry if this is duplicate. Any help is appreciated.
edit: Also the where clause, what query does it apply to? I assume the first select query but not really sure.

This create a Table with one row, which will be inserted, if soem conditions arrive see below
SELECT
? as hour,
? as uid,
? as lastupdate,
? as hash1hr
this will check if such a row exsist already in the Table stats_users_hour (same pid and lastupdate )
WHERE NOT EXISTS (
SELECT lastupdate FROM stats_users_hour WHERE lastupdate = ? AND uid = ?
)
And when such row exists,, so that now new row will be inserted
ON DUPLICATE KEY UPDATE lastupdate = ?, hash1hr = ?
This will update the row with the newest data for lastupdate and hash1hr

Related

fixing duplicate fields in mysql table with update statement

I have inherited a table with a field "sku" with should be unique, but thanks to a failing sku-generating method is now littered with dozens of duplicates all around.
I need to quickly fix these duplicates (other parts of the application are failing when encountering these duplicate records) by running an update and appending the record ID to the SKU (which is a valid solution for the time being for this application).
I'm trying to run:
UPDATE
main_product_table
SET sku = CONCAT(sku, '-', CAST(product_id as CHAR) )
WHERE sku IN (
SELECT sku FROM main_product_table
GROUP BY sku
HAVING COUNT(*) > 1
);
But I receive:
You can't specify target table 'main_product_table' for update in FROM clause
Is there a way to accomplish the same? Is mysql complaining about me having main_product_table both in the update and in the subquery to get the duplicates?
Thanks!
Try this:
UPDATE
main_product_table
SET sku = CONCAT(sku, '-', CAST(product_id as CHAR) )
WHERE sku IN (
select * from ( SELECT sku FROM main_product_table
GROUP BY sku
HAVING COUNT(*) > 1) as p
);
Added table alias in inner query.

Nested SELECT OR INSERT

I am quite new with writing mysql queries and so far things have been going well although I have recently become stuck with something. What I'm trying to do is select information from another table for use in the same query. Here's what I have so far which works fine:
SELECT *
FROM `userskinlist`
WHERE userid IN (
SELECT userid
FROM userlist
WHERE authid = 'STEAM_1:0:2144092'
)
AND active = '1'
AND weaponid >= '1'
AND skinid > '0'
But now if the nested part does not return anything
(SELECT userid FROM userlist WHERE authid = 'STEAM_1:0:2144092')
I need to run an insert statement as follows
INSERT IGNORE INTO userlist (authid) VALUES ('STEAM_1:0:2144092')`
but I can't figure out how to add this to the same query.
Any help would be greatly appreciated :)

MySQL - update the row with the highest start date

I am trying to update the member row with the highest start date using:
UPDATE at_section_details a
SET a.sd_end_date = ?
, a.sd_details = ?
WHERE a.cd_id = ?
AND a.sd_start_date = (SELECT MAX(b.sd_start_date)
FROM at_section_details b
WHERE b.cd_id = ?)
The error message is:
"SQLException in updateYMGroup: java.sql.SQLException: You can't specify target table 'a' for update in FROM clause
The table structure is:
sd_id - primary key
cd_id - foreign key (many occurrences)
sd_section
sd_pack
sd_start_date
sd_end_date
sd_details
A member (cd_id) can start and then transfer out.
The member can then transfer in again (new start date). When they transfer out we want to pick up the max start date to transfer out against.
Any assistance would be greatly appreciated.
Regards,
Glyn
You should be able to use the LIMIT statement with an ORDER BY. Something along these lines:
UPDATE at_section_details a
SET a.sd_end_date=?, a.sd_details=?
WHERE a.cd_id=?
ORDER BY a.sd_start_date DESC
LIMIT 1
As it says on this post MySQL Error 1093 - Can't specify target table for update in FROM clause
In My SQL you can't have an update with the same table you are updating inside a subquery.
I would try to change your sub query to some like this
(Select x.* from (select max...) as x)
Sorry for abbreviating the code, I'm on mobile.
This query should work:
UPDATE at_section_details
JOIN (
SELECT cd_id, MAX(sd_start_date) sd_start_date
FROM at_section_details
WHERE cd_id = ?
GROUP BY cd_id
) AS t2 USING (cd_id, sd_start_date)
SET sd_end_date=?, sd_details=?;
See this SQL Fiddle for an example
You can try this mate:
UPDATE at_section_details SET sd_end_date = <input>, sd_details = <input>
WHERE cd_id IN (
SELECT cd_id FROM at_section_details
WHERE cd_id = <input>
ORDER BY sd_start_date DESC
LIMIT 1
);

mySQL - INSERT query that matches the same records as this SELECT query?

I've got a select query I'm using to pick out contacts in my DB that haven't been spoken to in a while. I'd like to run an INSERT query to enter in a duplicate note for all the records that are returned with this select query... problem is I'm not exactly sure how to do it.
The SELECT query itself is likely a bit of a convoluted mess. I basically want to have the most recent note from each partner selected, then select ONLY partners that haven't got a note from a certain date and back... the SELECT query goes:
SELECT * FROM
(
SELECT * FROM
(
SELECT
partners.partners_id,
partners.CompanyName,
notes.Note,
notes.DateCreated
FROM
notes
JOIN
partners ON notes.partners_id = partners.partners_id
ORDER BY notes.DateCreated DESC
) AS Part1
GROUP BY partners_id
ORDER BY DateCreated ASC
) AS Part2
WHERE
DateCreated <= '2013-01-15'
How would a run an INSERT query that would only go into the same records as this SELECT?
The insert would enter records such as:
INSERT INTO notes
(
notes_id,
partners_id,
Note,
CreatedBy,
DateCreated
)
SELECT
UUID(),
partners.partners_id,
'Duplicated message!',
'User',
'2013-02-14'
FROM
partners
If you want to do this all in SQL, you could use an UPDATE statement.
UPDATE tablename SET note='duplicate' where id in ( your statement here);
Note that in order for this to work 'id' needs to be a column from 'tablename'. Then, your statement has to return a single column, not *. The column returned needs to be the id that will let your update statement know which rows to update in 'tablename'.

MySQL : selecting the X smallest values

Let be a table like this :
CREATE TABLE `amoreAgentTST01` (
`moname` char(64) NOT NULL DEFAULT '',
`updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`data` longblob,
PRIMARY KEY (`moname`,`updatetime`)
I have a query to find the oldest records for each distinct 'moname', but only if there are multiple records for this 'moname' :
SELECT moname, updatetime FROM amoreAgentTST01 a
WHERE (SELECT count(*) FROM amoreAgentTST01 x WHERE x.moname = a.moname) > 1
AND a.updatetime = (SELECT min(updatetime) FROM amoreAgentTST01 y WHERE y.moname = a.moname) ;
My question is : how to do the same but selecting the X oldest values ?
I now simply run this, delete the oldest values and rerun it... which is not so nice.
Seconds question is : what do you think of the above query ? can it be improved ? is there any obvious bad practice ?
Thank you in advance for your advices and help.
Barth
Would something like this work (untested):
SELECT moname, MIN(updatetime) FROM amoreAgentTST01
GROUP BY moname HAVING COUNT(moname)>1
Edit - the above is meant only as a replacement for your existing code, so it doesn't directly answer your question.
I think something like this should work for your main question:
SELECT moname, updatetime FROM amoreAgentTST01
GROUP BY moname, updatetime
HAVING COUNT(moname)>1
ORDER BY updatetime LIMIT 0, 10
Edit - sorry, the above won't work because it's returning only 10 records for all the monames - rather than the 10 oldest for each. Let me have a think.
One more go at this (admittedly, this one looks a bit convoluted):
SELECT a.moname, a.updatetime FROM amoreAgentTST01 a
WHERE EXISTS
(SELECT * FROM amoreAgentTST01 b
WHERE a.moname = b.moname AND a.updatetime = b.updatetime
ORDER BY b.updatetime LIMIT 0, 10)
AND (SELECT COUNT(*) FROM amoreAgentTST01 x WHERE x.moname = a.moname) > 1
I should add that if there is an ID column - generally the primary key- then that should be used for the sub-query joins for improved performance.