ORDER BY RAND() returns duplicates - php

I tried using distinct as well and it returns duplicates.
$cubes = mysql_query("SELECT distinct * FROM posts ORDER BY RAND() $limit ") or die(mysql_error());
I just want to take my posts table... and return it in a random order without duplicates.

Select only the distinct id's you need, e.g.
SELECT distinct id FROM posts ORDER BY RAND() $limit
Distinct works over 'all' rows you select, so if you (for example) have a unique timestamp field, chances are you'll return every single row.

Are you sure that you want to execute a SELECT DISTINCT * FROM ... and not just a SELECT DISTINCT column_name FROM ... ?
See the SQL DISTINCT STATEMENT doc for more infos.

Related

Mysql select all but first and last row

I want the database to show all the rows, except for the first and last ones, since I have CSS code for them.
I tried this:
SELECT * FROM db
WHERE
keywords LIKE '%example%' LIMIT 9999 OFFSET 1
AND
keywords LIKE '%example%' DESC LIMIT 9999 OFFSET 1
Since the row number may increase I can't write an exact number.
There really is no reason to complicate your query by trying to snip off these values at the SQL level, you could do:
$results = $db->query( /* regular query with all results */ );
array_pop($results);
array_shift($results);
// Now use $results, which now contains only the "middle" content
If you really want it at the DB level, you can use:
SELECT * FROM db
WHERE keywords LIKE '%example%'
AND id <> (SELECT MAX(ID) FROM TABLE)
AND id <> (SELECT MIN(ID) FROM TABLE)
You can use UNION like as
SELECT * FROM db WHERE keywords LIKE '%example%' order by keywords ASC limit 1 UNION SELECT * FROM db WHERE keywords LIKE '%example%' order by keywords DESC limit 1;
You can try this for instance:
SELECT * FROM TABLE WHERE ID != (SELECT MAX(ID) FROM TABLE) LIMIT 1,9844674507370
But like I said in the comment : It is strongly advisable that you handle this with PHP code, to avoid making 2 or more requests
You can do it without using LIMIT AND OFFSET
SELECT * FROM table_name WHERE id != (SELECT MAX(id) FROM table_name) AND id != (SELECT MIN(id) FROM table_name)
SELECT * FROM db
WHERE
keywords LIKE '%example%'
AND
id != (SELECT MAX(id) FROM db)
AND
id != (SELECT MIN(id) FROM db)
here id will be your auto increment key
1st : Simple you can handle this thing in php like below . avoid two query
$last_record =count($records)-1;
$i=0;
foreach($records as $key=>$row)
{
if($i==0){
//apply the css
}
if($i== $last_record ){
//apply the css
}
}
query :
SELECT * FROM db WHERE keywords LIKE '%example%'

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;

How can I order by count in mysql when the count need data to calculate from this select statement?

Look at my code, I want the select statement order by the count percentage after I fetch the data from this select statement, obviously, it's not logical. What can I do? Help, appreciate.
<?php
//myslq connection code, remove it because it's not relate to this question
$stm =$db->prepare("SELECT id ,term_count, COUNT(user_id) as count FROM sign WHERE term IN (:term_0,:term_1) GROUP BY user_id ORDER by count DESC");
//trying replace order by count with $combine_count, but it's wrong
$term_0="$term[0]";
$term_1="$term[1]";
$stm->bindParam(":term_0", $term_0);
$stm->bindParam(":term_1", $term_1);
stm->execute();
$rows = $stm->fetchALL(PDO::FETCH_ASSOC);
foreach ($rows as rows) {
$count=$rows['count'];
$term_count_number=$rows['term_count'];
$count_percentage=round(($count/$count_user_diff)*100);
$count_key_match=round(($count/$term_count_number)*100);
$combine_count=round(($count_percentage+$count_key_match)/2);
//issue is here, I want the select statement order by $combine_count
}
?>
SELECT id ,term_count, COUNT(user_id) as `count`
FROM sign
WHERE term IN (:term_0,:term_1)
GROUP BY user_id
ORDER by `count` DESC");
Since "count" is a function, it would be better to put backtics around the non-function "counts", as done above.
GROUP BY should list the field not aggregated. Otherwise, it does not know which id and term_count to fetch. So, depending on what you are looking for,
Either do
SELECT user_id, COUNT(*) as `count` -- I changed this line
FROM sign
WHERE term IN (:term_0,:term_1)
GROUP BY user_id
ORDER by `count` DESC");
or do
SELECT id ,term_count, COUNT(*) as `count`
FROM sign
WHERE term IN (:term_0,:term_1)
GROUP BY id ,term_count -- I changed this line
ORDER by `count` DESC");
SQL Syntax Logic
SELECT column1, count(column1) AS amount
FROM table_name
GROUP BY column1
ORDER BY amount DESC
LIMIT 12

Mysql ordering and then grouping a query in mysql

I need to order my query by date first...
So I used this:
SELECT * FROM `mfw_navnode` order by `id` DESC
I wanted to order my results from last to first.
Then what I am trying to do
is to add a query over it, which would group my results by node_name..
The result should be..all the top nodes grouped by "category/node name type", while the first node that I see is was ordered the highest for its category in the first query..
I thought to do something like this:
SELECT * FROM(
SELECT * FROM `mfw_navnode` order by `id` DESC) AS DD
WHERE (node_name='Eby' OR node_name='Laa' OR node_name='MIF' OR node_name='Amaur' OR node_name='Asn' )
GROUP BY DD.node_name
I get no result..or any response from phpmyadmin when I input that result..
Where do I get wrong?
Note , I dont want to group my results and then order them..
I want them to be ordered, and then grouped. After being grouped..I want the result of each group to have the highest value ..from the other rows in the group
It is not sufficient to perform the ordering first, as even then MySQL makes no guarantee over which record it will select for each group. From the manual:
The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate.
You must instead identify the records of interest with a subquery, then join the result with your table again in order to obtain the related values:
SELECT *
FROM mfw_navnode NATURAL JOIN (
SELECT node_name, MAX(id) AS id FROM mfw_navnode GROUP BY node_name
) AS DD
WHERE node_name IN ('Eby', 'Laa', 'MIF', 'Amaur', 'Asn')
Ordered by ID and group by node_name
SELECT * FROM `mfw_navnode`
WHERE (node_name='Eby' OR node_name='Laa' OR node_name='MIF' OR node_name='Amaur' OR node_name='Asn' )
GROUP BY DD.node_name
ORDER BY `id` DESC
Grouping is used commonly when You are using some aggregate function (sum, max, min, count, etc). If You don't use such function in Your query then why do You want to group the results?
Anyway, this should do the trick:
SELECT *
FROM mfw_navnode
WHERE id IN (SELECT id
FROM mfw_navnode
WHERE node_name IN ('Eby', 'Laa', 'MIF', 'Amaur', 'Asn')
GROUP BY node_name)
ORDER BY id
The following SQL may yield you the required output:
SELECT node_name, MAX(id)
FROM mfw_navnode
GROUP BY node_name
ORDER BY node_name
I see two problems with your SQL.
1) placing the order by in the inline select does nothing (and is probably causing an error)
2) you are grouping on node_name but you are not aggregating anything
SELECT COUNT(id) as row_count, node_name FROM( SELECT * FROM mfw_navnode ) AS DD
WHERE (node_name='Eby' OR node_name='Laa' OR node_name='MIF' OR node_name='Amaur' OR node_name='Asn' )
GROUP BY DD.node_name
order by node_name desc
further I am not sure why you need the inline select as the where could simply be on the original select ( perhaps you have something more complex going on that you didn't show )
SELECT COUNT(id) as row_count, node_name
from mfw_navnode
WHERE node_name='Eby' OR node_name='Laa' OR node_name='MIF' OR node_name='Amaur' OR node_name='Asn'
GROUP BY node_name
order by node_name desc

How do I fetch the last 15 rows in a table, then the 15 before that?

I want to return only the last 15 rows in my table, then the 15 before that.
Unfortunately while($rows = mysql_fetch_assoc($result)) where the query is SELECT * FROM table returns the data in all rows.
I thought about doing something like:
In my insert script
SELECT * FROM table then $selection_id = mysql_num_rows($result)-14 before inserting any data, then adding column named selection_id which would contain $selection_id, thus each set of 15 rows would have the same selection_id.
In my select script
SELECT * FROM table then $num_rows = mysql_num_rows($result)/15 then SELECT * FROM table WHERE selection_id='$num_rows' and SELECT * FROM table WHERE selection_id='$num_rows-1'.
I could then perform while(..) on both results as usual.
However, I'm not sure this is the most efficient way (chances are it's not), so if not, I'd really appreciate some suggestions to cut down the amount of code I'll have to use :)!!
Use a LIMIT clause in your query, order by your auto-incrementing primary key in descending order. E.g.
SELECT * FROM `table` ORDER BY `selection_id` DESC LIMIT 0,15
...will get the last 15 rows, and:
SELECT * FROM `table` ORDER BY `selection_id` DESC LIMIT 15,15
...will get the 15 rows before that.
Selecting the last 15 rows:
SELECT *
FROM `table`
ORDER BY `id` DESC
LIMIT 0,15
Selecting the 15 rows before the previous ones:
SELECT *
FROM `table`
ORDER BY `id` DESC
LIMIT 15,15
And you can continue in a while cycle.
You need to check out mysql LIMIT. To get the last 15, you'd need to know the number of total rows.
$offset=$rowcount-15;
$sql="SELECT * FROM mytable LIMIT $offset,15";
This is just for example, you'd want to make sure there are at least 15 rows, I'm not sure how mysql would deal with a negative offset. I'll let you figure out how to count the rows.
Edit:
Oh, haha, you could also just sort it descending, that will save you having to query twice.
SELECT * FROM mytable ORDER BY id DESC LIMIT 15;

Categories