Using more Subqueries - php

While I was using subqueries, I came across this situation. Could any one explain me which one is efficient and also, the situations where case 1 is better than case 2 or vice versa.
In case 1, I have used 3 subqueries and in total of 4 select operations, it need to perform.
CASE 1
SELECT * FROM t
WHERE Cid = (SELECT cid FROM s WHERE id = $sid)
AND Bid = (SELECT bid FROM s WHERE id = $sid)
AND Eid = (SELECT eid FROM s WHERE id = $sid)
In case 2, I have retrieved some values from database and perform mysql query again. Here mysqli_query is performed twice but in the case 1 only once we have used.
CASE 2
$res = mysqli_query($con,"SELECT cid,bid,eid FROM s WHERE id = $sid");
$row = mysqli_fetch_array($r,MYSQL_ASSOC);
"SELECT * FROM t WHERE Cid = $row[cid] AND Bid = $row[bid] AND Eid = $row[eid]";
or any other better solution? Any help is greatly appreciated. Thanks

Neither. You don't need subqueries when you can use a JOIN.
SELECT t.* FROM t
JOIN s ON t.Cid = s.cid AND t.Bid = s.bid AND t.Eid = s.eid
WHERE s.id = $sid

Related

Return one result per ChatID

I am getting data from a table and ordering them by a column in another table. Below is my query.
$query = "SELECT Chatroom.ChatID, Chatroom.User1, Chatroom.User2 FROM `Chatroom` JOIN `Messages` ON Chatroom.ChatID = Messages.ChatID WHERE User1 = ? OR User2 = ? ORDER BY Messages.MessageDate";
Say there is a chat between two people and they've messaged 10 times. I will get 10 results when really I want 1 result. I realize it's looping through messages because I joined them on chatID but I do that to get the dates.
Is there a better way to get this or is there any easy adjustment to my query that will work?
If you're using MySQL, maybe try this?
SELECT c.ChatID, c.User1, c.User2
FROM Chatroom AS c
JOIN (
SELECT mx.*
FROM Messages AS mx
WHERE mx.ChatID = c.ChatID
ORDER BY mx.MessageDate
LIMIT 1
) AS m ON m.ChatID = c.ChatID
WHERE c.User1 = ?
OR c.User2 = ?
ORDER BY m.MessageDate;
Try this instead?
SELECT c.ChatID, c.User1, c.User2
FROM Messages AS m
JOIN Chatroom AS c on c.ChatID = m.ChatID
WHERE (c.User1 = ? OR c.User2 = ?)
GROUP BY c.ChatID
ORDER BY m.MessageDate

SQL Order By id and Count star not working

I would like to get number of all records and get last record :
$sql_count_sms = "SELECT count(*) as total,content,id FROM android_users_sms WHERE user_id=$id ORDER BY id DESC";
$result_count_sms = mysql_query($sql_count_sms);
$row_num_sms = mysql_fetch_assoc($result_count_sms);
$num_sms = $row_num_sms['total'];
$last_my_sms = $row_num_sms['content'];
I can get number of records but I can't get last content record .
It returns first record !
Where is my wrong ?
Below codes works fine, but I think count(*) is faster than mysql_num_rows .
$sql_count_sms = "SELECT content,id FROM android_users_sms WHERE user_id=$id ORDER BY id DESC";
$result_count_sms = mysql_query($sql_count_sms);
$row_num_sms = mysql_fetch_assoc($result_count_sms);
$num_sms = mysql_num_rows($result_count_sms);
$last_my_sms = $row_num_sms['content'];
Any solution?
The grain of the two results you want is not the same. Without using a sub-query you can't combine an aggregate and a single row into the same result.
Think of the grain as the base unit of the result. The use of GROUP BY and aggregate functions can influence that "grain"... one result row per row on table, or is it grouped by user_id etc... Think of an aggregate function as a form of grouping.
You could break it out into two separate statements:
SELECT count(*) as total FROM android_users_sms WHERE user_id = :id;
SELECT * FROM android_users_sms WHERE user_id = :id ORDER BY id DESC LIMIT 1;
Also, specific to your question, you probably want a LIMIT 1 in combination with the ORDER BY to get just the last row.
Now, counter intuitively perhaps, this should also work:
SELECT count(*), content, id
FROM android_users_sms
WHERE user_id = :id
GROUP BY id, content
ORDER BY id
LIMIT 1;`
This is because we've changed the "grain" with the GROUP BY. This is the real nuance and I feel like this could probably be explained better than I am doing now.
You could also do this with a sub query like so:
SELECT aus.*,
(SELECT count(*) as total FROM android_users_sms WHERE user_id = :id) AS s1
FROM android_users_sms AS aus
WHERE user_id = :id ORDER BY id DESC LIMIT 1;

mysql get max value with multiple choices

i have this poll thing, Poll A, has 3 options let's say: Option a option b option c, option a got 3 votes, option b got 2 votes option c got 3 votes,
OPTIONS VOTES
option a 3
option b 2
option c 3
and i have this mysql query which gets the options and orders by votesCount, limit 1 to get the top answer, but in my example, there are two options on top, they both have the highest values, i want a query to get those two options, n not only one, so i have to get rid of LIMIT 1
Mysql query is
$query = "SELECT `option` FROM `options` WHERE `pid` = '$pid' AND `votesCount` != '0' ORDER BY `votesCount` DESC LIMIT 1";
any suggestion?
Here is a standard way in any SQL dialect:
select p.*
from poll p
where p.votes = (select max(votes) from poll)
Thanks to #Gordon Linoff for the hint, this is how it is now
$query = "SELECT `option` FROM `options` WHERE `pid` = '$pid' AND `votesCount` = (SELECT MAX(`votesCount`) FROM `options` WHERE `pid` = '$pid' ORDER BY `votesCount` DESC LIMIT 1)";
///Just a DB function, don't mind the 0, i'm using a class
$res = $db->get_rows($db->select($query),0);
$merged = array();
foreach ($res as $r){
$merged[] = $r->option;
}
$merged = implode(',',$merged);
return $merged;

Making 5 mysql queries into 1

I have mysql table with columns id, pos and status.
And I need to swap pos value of exact id with the nearest smaller pos value. But I need to count only rows with status = 1.
In other words it should work like this:
$pos = mysql_result(mysql_query("select pos from foo where id = $id"),0);
$min = mysql_result(mysql_query("select min(pos) from foo where status = 1"),0);
if($pos != $min){
$i = mysql_result(mysql_query("SELECT pos from foo where pos < $pos ORDER by pos DESC LIMIT 1"),0);
mysql_query("update tbc_sidebar set pos = $i where id = $id");
mysql_query("update tbc_sidebar set pos = pos + 1 where id <> $id AND pos = $i");
}
It works just fine like this, but I think it's not the best solution to have 5 queries because of one simple thing. Is there any way how to put it all into less queries? Thanks!
There are two thing you can do: use a stored procedure [1] [2] or send multiple queries at once with transaction. It kinda depends on which side you want to keep it all.
Also , i would strongly recommend for you to drop the old mysql_* functions as a way of accessing MySQL database. They are more then 10 years old, not maintained anymore and the community has begun the process of deprecation. You should not write new code with mysql_* in 2012. Instead you should learn how to use PDO or MySQLi as the API for accessing DB.
Here are two tutorials you might look at:
PDO Tutorial for MySQL Developers
Introduction to PHP PDO
I have not tried this but it should work. It is not pretty!
UPDATE tbc_sidebar main
INNER JOIN (
SELECT t1.id id1, t1.pos pos1, t2.id id2, t2.pos pos2
FROM tbc_sidebar t1
INNER JOIN tbc_sidebar t2
ON t1.pos > t2.pos
AND t2.status = 1
WHERE t1.id = $id
ORDER BY t2.pos DESC
LIMIT 1
) AS tmp
ON main.id = tmp.id1 OR main.id = tmp.id2
SET main.pos = CASE
WHEN main.id = tmp.id1 THEN tmp.pos2
WHEN main.id = tmp.id2 THEN tmp.pos1
END
Store procedure is a best choice to execute multiple queries together.

Simplify two MySQL queries by merging them into 1?

I have two MySQL queries which are very similiar however they return a COUNT() upon a specific WHERE clause (type), so I was wondering if they could be merged into 1 query seeing as only the WHERE clause (type) differenciates the two?
Query 1:
SELECT COUNT(referral_id) AS in_count
FROM referrals
WHERE author = '{$author}'
AND type = 'in'
AND ip_address = '{$ip_address}'
LIMIT 1
Query 2:
SELECT COUNT(referral_id) AS out_count
FROM referrals
WHERE author = '{$author}'
AND type = 'out'
AND ip_address = '{$ip_address}'
LIMIT 1
All help is greatly appreciated :B
SELECT SUM(IF(type='in',1,0)) as in_count,
SUM(IF(type='out',1,0)) as out_count
FROM referrals
WHERE author = '{$author}' AND
ip_address = '{$ip_address}'
LIMIT 1
You just need a GROUP BY clause.
SELECT COUNT(referral_id) AS count, type
FROM referrals
WHERE author = '{$author}'
AND ip_address = '{$ip_address}'
GROUP BY type
LIMIT 1

Categories