About a query and subquery - mysql

this is my query, and I already know the problem but I dont have an idea about how to solve it:
$queryString = "SELECT * FROM `users_list` "WHERE `user_id` like (SELECT `user_id` FROM `equipments_list` WHERE `equipment_mac` like '%$searchStringMacRevised%')"
So, this is the error sometimes I get:
Subquery returns more than 1 row
I see that the problem is that if the mac address is registered more than once, it will give me more than one user ID, and when we are going to select the information, I have too much user id to generate the table. Can you guys help me to see how can I solve this problem?

Since you are just comparing to the user id directly, you could use an IN clause, such as
SELECT * FROM users_list
WHERE user_id IN
(SELECT user_id FROM equipments_list
WHERE equipment_mac like '%$searchStringMacRevised%')
This would allow you to potentially compare to multiple user ids.
If we want only 1 user id, then you may need to use the LIMIT type of query suggested in other answers.

It means that your inner select is returning more than one row , it should exactly return 1 row in order to match record for outer query
$queryString = "SELECT * FROM `users_list` "WHERE `user_id` like (SELECT `user_id` FROM `equipments_list` WHERE `equipment_mac` like '%$searchStringMacRevised%' LIMIT 1)"

Related

Get Conditionally Latest record from each group - without Aggregate functions or Partition

I have been trying to do this in many ways suggested.
Note: we do not want aggregate function or Partition since this is just a small part of whole Stored procedure and this is client requirement to not have it, so not in option and not possible duplicate of other existing answers / questions
I have a messages table, which has a column from and to, a foreign key to the user table, basically which user sends to whom at simplest. I also have other columns which are isSnoozed and snoozeAt for if the message is snoozed.
So the ordering is according to case. If messages is snoozed then consider snoozeAt time to Order or if not then consider sendAt. (right now we can ignore this condition while ordering, But I mentioned this since we cannot take simply MAX(id) )
I need to get recent most message from messages group by from user id
messages table like :
id -- to -- from -- isSnoozed -- snoozedAt -- sendAt ...
What I tried :
select * from ( select * from messages order by sendAt DESC) as TEMP GROUP BY TEMP.from
I tried many similar approaches but none worked.
I wasted many paid hours but can't find an approach which meets my exact requirement
NOTE: Please ignore typo in query if any, since I cant type in exact query table and names, So i typed in directly here
I figured this out by doing something like this, which could be explained in a simplified way:
select * from message where message.id in (
select
( select id from message where message.from = user.id order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC limit 1) as id
from user where user.id in ( select friends.`whoIsAdded` from friends where friends.`whoAdded` = myId)
) order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC
If I understand correctly, you just want the largest value in one of two columns. Assuming the values are never NULL, you can use greatest():
select m.*
from messages m
where greatest(m.sendAt, m.snoozedAt) =
(select max(greatest(m2.sendAt, m2.snoozedAt))
from messages m2
where m2.from = m.from
);
If the columns can be NULL, then you can use coalesce() to give them more reasonable values.

Having multiple statements on where clause with same column name

I have a sample SQL statement that says:
SELECT * from users WHERE id = 2 OR id = 5 OR id = 7
What I would like is to avoid repeating id each time in the where clause. Is there a shortcut for this in MySQL that will allow me to mention the id only once?
Yes, the IN clause
SELECT * from users WHERE id IN(2,5,7);
if these Ids you are using in the comparison come from another table you can even do
SELECT * FROM users WHERE id in (SELECT other_id FROM other_table WHERE somecondition)
e4c5 gave you the answer you needed, but here is something else you can do with IN:
select * from users where 'steve' IN (users.fname, users.lname)

MySQL Query returning invalid rows and very slow

I am writing an query to select player bans from another table but firstly its very slow taking around 7-14 seconds and secondly its returning invalid rows.
The first query is as follows:
SELECT *
FROM sourcebans.sb_bans
WHERE removetype IS NULL
AND removedon IS NULL
AND reason NOT LIKE '%[FragSleuth] Duplicate account%'
AND ip IN(SELECT DISTINCT ip
FROM fragsleuth.history
WHERE trackingid = "ad000c3803b48190aabf382e01b957c9")
OR authid IN(SELECT DISTINCT steamid
FROM fragsleuth.history
WHERE trackingid = "ad000c3803b48190aabf382e01b957c9")
The second query is as follows
SELECT * FROM `history` WHERE trackingid = "ad000c3803b48190aabf382e01b957c9"
And a couple of screenshots to show what I mean:
First Query Second Query
In screenshot 1 you can see that its returning a row where the removedon and removetype is not null when I asked the query to only return rows with NULL.
I am also afraid that inside the history table there will be duplicate entries for the steamid and ip columns which might make the query slow, is there any way to make the query only select rows with a unique ip or steamid based on the trackingid?
Any help would be much appreciated.
Thanks
Edit: I am overwhelmed by the help, Thanks to #maraca, #Skorpioh and #Adam Silenko, the query time is now less than a second!
the and have higher priority then or...
You need have to index on your tables
np. add index to trackingid field in fragsleuth.history if you don't have
You can probably do faster using one sub query, but i'm not sure this.
SELECT *
FROM sourcebans.sb_bans
WHERE removetype IS NULL
AND removedon IS NULL
AND reason NOT LIKE '%[FragSleuth] Duplicate account%'
AND exists (
SELECT 1 from fragsleuth.history
WHERE trackingid = "ad000c3803b48190aabf382e01b957c9"
and (ip = sourcebans.ip or steamid = sourcebans.authid) )
The query returns rows that are not NULL because it is interpreted as (... AND ... AND ... ) OR ... instead of ... AND ... AND ( ... OR ...)
So you need to add a braces, also the DISTINCT is not needed:
SELECT *
FROM sourcebans.sb_bans
WHERE removetype IS NULL
AND removedon IS NULL
AND reason NOT LIKE '%[FragSleuth] Duplicate account%'
AND (ip IN(SELECT ip
FROM fragsleuth.history
WHERE trackingid = "ad000c3803b48190aabf382e01b957c9")
OR authid IN(SELECT steamid
FROM fragsleuth.history
WHERE trackingid = "ad000c3803b48190aabf382e01b957c9"))
You have an operatior precendence issue here and that's why it ends up having results where removetype/removedon isn't null.
If you check http://dev.mysql.com/doc/refman/5.7/en/operator-precedence.html you'll see that AND is higher priority than OR meaning your query will run all the predicates glued together with the "AND" operator and only afterwards do the OR meaning you will see results where the authorid is a match and the rest doesn't matter anymore.
If I'm not wrong the below should work correctly:
SELECT *
FROM sourcebans.sb_bans
WHERE removetype IS NULL
AND removedon IS NULL
AND reason NOT LIKE '%[FragSleuth] Duplicate account%'
AND
(
ip IN (SELECT DISTINCT ip
FROM fragsleuth.history
WHERE trackingid = "ad000c3803b48190aabf382e01b957c9")
OR
authid IN(SELECT DISTINCT steamid
FROM fragsleuth.history
WHERE trackingid = "ad000c3803b48190aabf382e01b957c9")
)
Regarding speed improvements, you should create a covering index for the removetype, removedon, ip and authid columns first. This will help but likely won't be enough as the LIKE operation is very expensive.
The last thing you should do is to check if you can change
reason NOT LIKE '%[FragSleuth] Duplicate account%'
into something else. Can you for example eliminate the leading % so it can at least do a much faster match? Depends of course on what exactly those columns store.

Trying to count my count

So I have and email data base and where each email send has it's own line. I'm trying to figure out how many times each user is being sent to. So I'm using this query to find out out how many times each user has been mailed.
SELECT count(`id`)
FROM `bde_export`
WHERE `record.type` = 'senttomta'
GROUP BY `user.id`
Now what I'm trying to do is count that count so I get a summary telling me how many users have been mailed 1,2,3,4 times and so on. I know that is a bit confusing please let me know if clarification is needed.
well why dont you try another count???
like this
SELECT count(`tmp`.*) FROM (
SELECT count(`id`)
FROM `bde_export`
WHERE `record`.`type` = 'senttomta'
GROUP BY `user`.`id`
) `tmp`
i dont know what exactly is your problem but with current explanation i think it works. i just copied your query and didnt change that.
but if it doesn't satisfy your meets, i suggest you to try this:
SELECT sum(`tmp`.`count`) FROM (
SELECT count(`id`) AS `count`
FROM `bde_export`
WHERE `record`.`type` = 'senttomta'
GROUP BY `user`.`id`
) `tmp`
You can do this with two selection statements.. try something like this..
SELECT SUM(s.EmailCount) as 'TotalCount', s.id
FROM
(
SELECT COUNT(id) as 'EmailCount', id
FROM
GROUP BY user.id
) AS s
GROUP BY s.EmailCount
Basically you do your initial select statement and select the sum of the initial count

MySQL Subquery in SELECT statement

I am using MySQL and am getting an error when if I try to excute a subquery... my subquery is as follows:
sponsor_id columns contains 10 record with id (auto increment).
SELECT * FROM user where id=(select id from user where sponsor_id ='10002')
Thanks in advance
use IN instead of = .
SELECT * FROM user where id IN (select id from user where sponsor_id ='10002' AND id IS NOT NULL)
The reason is that your subquery is most probably returning more than one values. It should return only one value if you are using the equals to operator.
Else use the IN clause as:
SELECT * FROM user where id IN (select id from user where sponsor_id ='10002')
Edit:
You may also use an INNER JOIN or any other JOIN for that matter that suits your purpose.
you are getting the error because '=' will operate on a single value not on the multiple values.so use 'IN' opeartor or make sure that your subquery returns only a single value while using '='.
Try this
SELECT * FROM user where id IN (select id from user where sponsor_id ='10002')
or:
SELECT * FROM user where id =(select id from user where sponsor_id ='10002' Limit 1)