Order of "id" changed in subquery? - mysql

I have this query
SELECT bul.id
FROM bul
WHERE id IN (SELECT hotid AS parentid
FROM likehot
WHERE hotid IN (SELECT id
FROM bul
WHERE DATE >= '1315976410')
GROUP BY hotpid
ORDER BY COUNT( hotid ) DESC )
when I runt this inner query
SELECT id
FROM bul
WHERE DATE >= '1315976410')
GROUP BY hotpid
ORDER BY COUNT( hotid ) DESC
I get
parentid
3655
3656
3622
3644
and when I run whole query I get
parentid
3656
3655
3622
3644
I really don't understand why the order of the ids change?
SOLUTION :-
<?php
$query_hotpress_like = "SELECT hotid AS parentid FROM likehot WHERE hotid IN (SELECT id FROM bul WHERE DATE >= '" . (time() - (24 * 60 * 60)) . "') GROUP BY hotid ORDER BY COUNT( hotid ) DESC";
$exe_hotpress_like = execute_query($query_hotpress_like, true, "select");
$temp_like1 = array();
foreach ($exe_hotpress_like as $kk => $exe_like) {
$temp_like1[] = "'" . $exe_like['parentid'] . "'";
}
$temp_like = str_replace(",''", "", implode(',', $temp_like1));
$query_hotpress = "SELECT bul.id,photo_album_id,eventcmmnt_id,link_url,youtubeLink,link_image,id, mem_id, subj, body, bul.date,parentid, from_id, visible_to,image_link,post_via FROM bul WHERE id IN ($temp_like) ORDER BY FIELD(id,$temp_like ) LIMIT 5";
?>
execute_query() is the inbuilt function to get the result of query.

That happens because for IN operator order doesn't matter.
If you need to sort outer query - sort outer query.

Since you didn't specify an order for the "whole" query, the database is at liberty to return rows in any order it wants. The specific order you get is a result of how looking up rows is done when using the IN operator.
On your other query you are specifying an order yourself, so the database has to honor it.

Related

SQL query with a major NOT IN not working

Does anyone know what's wrong with this query?
This works perfectly on its own:
SELECT * FROM
(SELECT * FROM data WHERE site = '".$id."'
AND disabled = '0'
AND carvotes NOT LIKE '0'
AND (time > ( now( ) - INTERVAL 14 DAY ))
GROUP BY car ORDER BY carvotes DESC LIMIT 0 , 10)
X order by time DESC
So does this:
SELECT * FROM data WHERE site = '".$id."' AND disabled = '0' GROUP BY car DESC ORDER BY time desc LIMIT 0 , 30
But combining them like this:
SELECT * FROM data WHERE site = '".$id."' AND disabled = '0' AND car NOT IN (SELECT * FROM
(SELECT * FROM data WHERE site = '".$id."'
AND disabled = '0'
AND carvotes NOT LIKE '0'
AND (time > ( now( ) - INTERVAL 14 DAY ))
GROUP BY car ORDER BY carvotes DESC LIMIT 0 , 10)
X order by time DESC) GROUP BY car DESC ORDER BY time desc LIMIT 0 , 30
Gives errors. Any ideas?
Please try the following...
$result = mysqli_query( $con,
"SELECT *
FROM data
WHERE site = '" . $id .
"' AND disabled = '0'
AND car NOT IN ( SELECT car
FROM ( SELECT car,
carvotes
FROM data
WHERE site = '" . $id .
"' AND disabled = '0'
AND carvotes NOT LIKE '0'
AND ( time > ( NOW( ) - INTERVAL 14 DAY ) )
GROUP BY car
ORDER BY carvotes DESC
LIMIT 10 ) X
)
GROUP BY car
ORDER BY time DESC
LIMIT 30" );
The main cause of your problem is that with car NOT IN ( SELECT * FROM ( SELECT *... you are trying to compare each record's value of car with each row returned by your subquery. IN requires you to have the same number of fields on both sides of the comparison. By using SELECT * at both levels of the subquery you were ensuring that the right side of the comparison had however many fields are in data versus your single field on the left, which confused MySQL.
Since you are aiming to compare to a single field, namely car, our subquery has to select just the car field from its dataset. Since the sort order of the subquery's results has no effect upon the IN comparison, and since our innermost query will be returning just car, I have removed the outer level of the subquery.
Beyond changing the first part of the subquery to SELECT car, the only other change that I have made to the subquery is to change LIMIT 0, 10 to LIMIT 10. The former means limit to the the 10 records that are offset by 0 from the first record. This is useful if you want records 6 to 15, but redundant for 1 to 10 as LIMIT 10 has the same affect and is slightly simpler. Ditto for LIMIT 0, 30 at the end of your overall statement.
As for the main body of the statement, I have not made any attempt to specify what fields (or aggregate functions of those fields) should be returned since you have made no statement indicating what your requirements / preferences are. If you are satisfied that GROUP BY has left you with a still valid set of values, then all the good, but if not then I recommend that you rewrite your Question to be specific about that detail.
By default, MySQL sorts the data subjected to a GROUP BY into ascending order, but if an ORDER BY clause is also present then it overrides the GROUP BY's sort pattern. As such, there is no benefit to specifying DESC after either of your GROUP BY car clauses, so I have removed it where it occurs.
Interesting Sidenote : You can override a GROUP BY's sort by specifying ORDER BY NULL.
If you have any questions or comments, then please feel free to post a Comment accordingly.
Further Reading
https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html - on optimising your ORDER BY sorting
https://dev.mysql.com/doc/refman/5.7/en/select.html - on the SELECT statement's syntax - specifically the parts to do with LIMIT.
https://www.w3schools.com/php/php_mysql_select_limit.asp - a simpler explanation of LIMIT
This is your query:
SELECT *
FROM data
WHERE site = '".$id."' AND disabled = '0' AND
car NOT IN (SELECT *
FROM (SELECT *
FROM data
WHERE site = '".$id."' AND
disabled = '0' AND
carvotes NOT LIKE '0' AND
(time > ( now( ) - INTERVAL 14 DAY ))
GROUP BY car
ORDER BY carvotes DESC
LIMIT 0 , 10
) x
ORDER BY time DESC
)
GROUP BY car DESC
ORDER BY time desc
LIMIT 0 , 30 ;
Several comments:
Do not wrap integer constants in single quotes. This can mislead people. This can mislead optimizers.
Do not use string functions on integers (such as like). Same reason.
NOT IN with subqueries is dangerous. The construct does not handle NULL values the way you expect. Use NOT EXISTS or LEFT JOIN instead.
When using subqueries, ORDER BY is almost never appropriate.
Never use SELECT * with GROUP BY. It is just wrong. Happily, MySQL 5.7 has changed its defaults to reject this anti-pattern
So, a better way to write this query is something like this:
SELECT d.car, MAX(time) as time
FROM data d LEFT JOIN
(SELECT d2.*
FROM data d2
WHERE d2.site = '".$id."' AND
d2.disabled = 0 AND
d2.carvotes NOT LIKE 0 AND
(d2.time > ( now( ) - INTERVAL 14 DAY ))
GROUP BY d2.car
ORDER BY carvotes DESC
LIMIT 0 , 10
) car10
ON d.car = car10.car
WHERE d.site = '".$id."' AND d.disabled = 0' AND
car10.car IS NOT NULL
GROUP BY car DESC
ORDER BY MAX(time) desc
LIMIT 0 , 30 ;
Alternatively, use SELECT * and remove the GROUP BY in the outer query.

How to subtract two calculated fields from the same table in MySQL?

SELECT *,
SUM(price+shipping+paypalfee+storefee) AS totalcost,
customerpaid AS totalrevenue,
(totalcost - totalrevenue) AS profit
FROM tblsales
GROUP BY orderno
HAVING " . $having . "
ORDER BY $sort $order
LIMIT $offset,$rows
If I omit (totalcost - totalrevenue) as profit the query works fine. How could I calculate PROFIT in the same query using totalcost and totalrevenue?
The answer to your question is that you have to repeat the expressions:
select *, sum(price+shipping+paypalfee+storefee) as totalcost
customerpaid as totalrevenue,
(sum(price+shipping+paypalfee+storefee) - customerpaid) as profit
from tblsales
group by orderno
having " . $having . "
order by $sort $order
limit $offset, $rows;
You are not allowed to use a column alias in the same select where it is defined.
And, your query looks weird. Any query that has select * and group by is suspect. You have many columns (presumably) whose value will come from an indeterminate row for each group. You should explicitly list the columns in general, but you should especially do so for a group by.
You can do like this
SELECT * , (totalcost - totalrevenue) AS profit FROM(
SELECT *,
SUM(price+shipping+paypalfee+storefee) AS totalcost,
customerpaid AS totalrevenue,
FROM tblsales
GROUP BY orderno
HAVING " . $having . "
ORDER BY $sort $order )
LIMIT $offset,$rows

Where to put WHERE in mysql query

I cannot find where I can put my WHERE clause in my query. It seems like I tried every possible position but nothing is working.
SELECT res
FROM (
SELECT `date`,SUM(DISTRIBUTED_AMOUNT / EXCHANGE_RATE) AS res
FROM royalties
GROUP BY `date`
ORDER BY `date` DESC LIMIT 12
) a
ORDER BY `date` ASC
WHERE `BUNDLE_ARTIST` = '" . $artist_name . "'
I'd have thought you need to put it after the FROM clause in the subquery:
SELECT res
FROM (
SELECT `date`,SUM(DISTRIBUTED_AMOUNT / EXCHANGE_RATE) AS res
FROM royalties
WHERE `BUNDLE_ARTIST` = '" . $artist_name . "'
GROUP BY `date`
ORDER BY `date` DESC LIMIT 12
) a
ORDER BY `date` ASC
You can see this order documented in the MySQL manual.
It seems that you are using an inner query in your clause. You made some mistakes. Try this:
SELECT res
FROM
(
SELECT `date`,SUM(DISTRIBUTED_AMOUNT / EXCHANGE_RATE) AS res
FROM royalties
WHERE `BUNDLE_ARTIST` = '" . $artist_name . "'
GROUP BY `date`
ORDER BY `date` DESC LIMIT 12
) inner query
ORDER BY `date` ASC
Usually, I find including your WHERE clause before the ORDER and GROUP clauses is best:
SELECT res
FROM (
SELECT `date`,SUM(DISTRIBUTED_AMOUNT / EXCHANGE_RATE) AS res
FROM royalties
GROUP BY `date`
ORDER BY `date` DESC LIMIT 12
)
WHERE `BUNDLE_ARTIST` = '" . $artist_name . "'
ORDER BY `date` ASC

Get last X rows using LIMIT and ORDER BY col ASC

This query is to retrieve some messages, it retuns all of them:
$q = "
SELECT *
FROM pms
WHERE
(
(id_to = $id and id_from = ".sesion().")
OR
(id_from = $id and id_to = ".sesion().")
)
AND (id > $from)
ORDER by fecha ASC";
The thing is i would like to get the last 50 elements, but I think its ony posible using DESC ordering..
how can i do it?
Do i need to count first how many rows so then can I use LIMIT $many-$ipp,$many ? or is there a way to invert the result order?
Just make your query a subquery:
SELECT * FROM
(
SELECT *
FROM pms
WHERE
(
(id_to = $id AND id_from = ".sesion().")
OR (id_from = $id and id_to = ".sesion().")
)
AND id > $from
ORDER BY fecha DESC
LIMIT 50
) q1
ORDER BY fecha ASC

Exclude results of the first query on the second query in same table with MySQL

I want to do like this:
SELECT * FROM `langCategories` ORDER BY `name` ASC WHERE ORDER BY `amount` DESC LIMIT 8,0
but this is not posible.
I have 2 sections in my site:
1. Top 8 Populars Categories
(SELECT * FROM `langCategories` ORDER BY `langCategories`.`amount` DESC LIMIT 0,8)
2. The rest of Categories order by name (excluding the top 8)
(???)
I do it with php:
$var = db_multiselect("SELECT * FROM `langCategories` ORDER BY `amount` DESC LIMIT 0,8");
$var2 = db_multiselect("SELECT * FROM `langCategories` ORDER BY `name` ASC");
$i=-1;
while ($row = mysqli_fetch_array($var)) // Save the top8 categories
{
++$i;
$top8[$i] = $row["name"];
}
$i=0;
while ($row2 = mysqli_fetch_array($var2))
{
if (!(in_array($row2["name"], $top8))) // compare the rest of categories excluding top 8
{
...
}
}
But i want to do this with a MySQL Query, how can do it?
Subquery!
SELECT * FROM (
SELECT * FROM `langCategories`
ORDER BY `langCategories`.`amount` DESC
LIMIT 8,2000000000
) AS baseview
ORDER BY name ASC
Gives you the NOT top 8 categories in alphabetical order
this should work for MySQL (i hope):
SELECT *
FROM (
SELECT lc.*, #rownum:=#rownum+1 AS rownum
FROM `langCategories` lc, (SELECT #rownum:=0) r
ORDER BY `amount` DESC
)
ORDER BY CASE WHEN rownum <= 8 THEN rownum ELSE 999 END, name