Nested SELECT OR INSERT - mysql

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 :)

Related

Explain insert query with select queries inside

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

Select records that don't exist in another DB table

I'm trying to tackle what I thought was a simple query.
I have two databases each with one table in the DB.
What I would like to do is find all of the emails from DB1.Table that don't exist in DB2.Table
I'm using this query, but the result is incorrect because I know DB1.Table contains emails that don't exist in DB2.Table (result always comes back as 0)
SELECT DB1.20180320.email
FROM DB1.20180320
WHERE DB1.20180319.email NOT IN
(SELECT DB2.20180319.email FROM DB2.20180319 WHERE Status = 'active')
Any ideas on what I'm doing wrong here? I'm working with about 80k rows in each table.
Thanks.
without seeing your data, try something like this.
SELECT DB1.20180320.email
FROM DB1.20180320
left join DB2.20180319 on DB1.20180320.email = DB2.20180319.email
AND DB2.20180319.Status = 'active'
WHERE DB2.20180319.email IS null;
This should show all the emails in DB1.20180320 that don't exist in DB2.20180319
NOT EXISTS query should do it. It returns email that exist in DB1, but not DB2.
SELECT DB1.20180320.email
FROM DB1.20180320
WHERE NOT EXISTS(
SELECT 1
FROM DB2.20180319
WHERE DB1.20180320.email = DB2.20180319.email
AND DB2.20180319.Status = 'active'
)

Converting sql query to ActiveRecord Rails

I have a location table in my database which contains location data of all the users of my system.
The table design is something like
id| user_id| longitude| latitude| created_at|
I have an array of users. Now I want to select the latest(sorted according to created at) location of all these users.
I am able to figure out the sql query for same
SELECT * FROM my_table
WHERE (user_id , created_at) IN (
SELECT user_id, MAX(created_at)
FROM my_table
GROUP BY user_id
)
AND user_id IN ('user1', 'user2', ... );
Now as I am working in Ruby On Rails, I want to write this sql query to activerecord rails. Can anyone please help me with this ?
I think this will give the correct result:
MyModel.order(created_at: :desc).group(:user_id).distinct(:user_id)
If you want to generate the exact same query, this will do it:
MyModel.where("(user_id, created_at) IN (SELECT user_id, MAX(created_at) from my_table GROUP BY user_id)")
I think the subquery will probably not scale well with a large data set, but I understand if you just want to get it into rails and optimize later.
How about adding a scope, and getting the same result in a slightly different way:
class UserLocation
def self.latest_per_user
where("user_locations.created_at = (select Max(ul2.created_at) from user_locations ul2 where ul2.user_id = user_locations.user_id)")
end
end
Then you just use:
UserLocation.latest_per_user.where(:user_id => ['user1', 'user2'])
... to get the required data set.

Why does column_name = (select column_name) work and not column_name=null

I am fetching some rows for my model but the view has so many criteria i was getting tired of writing many models.To make work easier i don't want to write new select statements for every criteria selected so at first i tried to try and still return something from the select even when one of more of the available criteria are/is not supplied by the user.
SELECT * FROM members WHERE member_id = null AND member_club_id = 1 AND membership_year = null;
and returns nothing
Finally i tried
SELECT * FROM members WHERE member_id = (select member_id) AND member_club_id = (select member_club_id=1) AND membership_year = (select membership_year);
and this works correctly.
I am still new to mysql and i wanted to know why this second approach worked.
Of interest is select member_club_id=1 and member_id = (select member_id) for instance.
In member_id = (select member_id) i was thinking this would be read as member_id=member_id since i had no variable called member id and therefore fail.
In select member_club_id=1 i thought i would get unknown column error in member_club_id and therefore fail.
Someone help out.
You can't use = with NULL. Use IS NULL or IS NOT NULL.
see: http://dev.mysql.com/doc/refman/5.0/en/working-with-null.html
in first query you maybe want do this
SELECT * FROM members WHERE member_id is null
AND member_club_id = 1
AND membership_year is null;
there is not in mysql = null but is null
in your second query i dont think this member_id = (select member_id) will do something
its like you saying WHERE member_id = member_id this automatically return true in all cases. Thats why you got it working.

Update with SELECT and group without GROUP BY

I have a table like this (MySQL 5.0.x, MyISAM):
response{id, title, status, ...} (status: 1 new, 3 multi)
I would like to update the status from new (status=1) to multi (status=3) of all the responses if at least 20 have the same title.
I have this one, but it does not work :
UPDATE response SET status = 3 WHERE status = 1 AND title IN (
SELECT title FROM (
SELECT DISTINCT(r.title) FROM response r WHERE EXISTS (
SELECT 1 FROM response spam WHERE spam.title = r.title LIMIT 20, 1)
)
as u)
Please note:
I do the nested select to avoid the famous You can't specify target table 'response' for update in FROM clause
I cannot use GROUP BY for performance reasons. The query cost with a solution using LIMIT is way better (but it is less readable).
EDIT:
It is possible to do SELECT FROM an UPDATE target in MySQL. See solution here
The issue is on the data selected which is totaly wrong.
The only solution I found which works is with a GROUP BY:
UPDATE response SET status = 3
WHERE status = 1 AND title IN (SELECT title
FROM (SELECT title
FROM response
GROUP BY title
HAVING COUNT(1) >= 20)
as derived_response)
Thanks for your help! :)
MySQL doesn't like it when you try to UPDATE and SELECT from the same table in one query. It has to do with locking priorities, etc.
Here's how I would solve this problem:
SELECT CONCAT('UPDATE response SET status = 3 ',
'WHERE status = 1 AND title = ', QUOTE(title), ';') AS sql
FROM response
GROUP BY title
HAVING COUNT(*) >= 20;
This query produces a series of UPDATE statements, with the quoted titles that deserve to be updated embedded. Capture the result and run it as an SQL script.
I understand that GROUP BY in MySQL often incurs a temporary table, and this can be costly. But is that a deal-breaker? How frequently do you need to run this query? Besides, any other solutions are likely to require a temporary table too.
I can think of one way to solve this problem without using GROUP BY:
CREATE TEMPORARY TABLE titlecount (c INTEGER, title VARCHAR(100) PRIMARY KEY);
INSERT INTO titlecount (c, title)
SELECT 1, title FROM response
ON DUPLICATE KEY UPDATE c = c+1;
UPDATE response JOIN titlecount USING (title)
SET response.status = 3
WHERE response.status = 1 AND titlecount.c >= 20;
But this also uses a temporary table, which is why you try to avoid using GROUP BY in the first place.
I would write something straightforward like below
UPDATE `response`, (
SELECT title, count(title) as count from `response`
WHERE status = 1
GROUP BY title
) AS tmp
SET response.status = 3
WHERE status = 1 AND response.title = tmp.title AND count >= 20;
Is using GROUP BY really that slow ? The solution you tried to implement looks like requesting again and again on the same table and should be way slower than using GROUP BY if it worked.
This is a funny peculiarity with MySQL - I can't think of a way to do it in a single statement (GROUP BY or no GROUP BY).
You could select the appropriate response rows into a temporary table first then do the update by selecting from that temp table.
you'll have to use a temporary table:
create temporary table r_update (title varchar(10));
insert r_update
select title
from response
group
by title
having count(*) < 20;
update response r
left outer
join r_update ru
on ru.title = r.title
set status = case when ru.title is null then 3 else 1;