Return random result from three SQL tables - php

I have an SQL database with three tables inside called...
Fruit Name
Fruit Color
Fruit Price
I am attempting to return a random result from each of these three tables to give me for example....
Apple - Green - $10
Currently I am doing this by running the following PHP three times (with a different table for each)
$result = mysqli_query($con,"SELECT * FROM fruitname");
while($row = mysqli_fetch_array($result))
{
echo $row['fruitname'];
}
This works fine but I get the feeling I am going about it the wrong way. Is there a way to do this as one command instead of three?

If you really want a random row, you can do it this way:
select *
from (select * from FruitName order by rand() limit 1) fn cross join
(select * from FruitColor order by rand() limit 1) fc cross join
(select * from FruitPrice order by rand() limit 1) fp
This returns all the fields in one row.
Note that a random row is very different from an arbitrary row. A random row really means that each row has an equal chance of being selected. An arbitrary row is simply indeterminate. The first row in a select without an order by is arbitrary, but definitely not random.

Related

How can to select a random row from a MySQL database in PHP?

I have a database table questions on a online web server with 2000+ rows and I need to get 6 randomly selected rows. They must be different so that one question is not two times in the list array of 6 questions.
How can I achieve this?
You have a relatively small amount of data, so the simplest method is:
select q.*
from questions q
order by rand()
limit 6;
In this query, the order by takes the longest amount of time. Ordering 2,000 rows might be noticeable. A simple fix is to reduce the number of rows being ordered. One method is:
select q.*
from questions q cross join
(select count(*) as cnt from questions) m
where rand() < 100 / m.cnt
order by rand()
limit 6;
The where selects about 100 rows randomly and then orders those to select 6. You are pretty much guaranteed that the where will always choose at least 6 rows.
Use the DISTINCT operator in MySQL:
SELECT DISTINCT column FROM table ORDER BY RAND() LIMIT 6;
So DISTINCT will take care and remove duplicates

MYSQL Query - order by and then select random of the same value

I'm currently looking in MySQL to order results by price, and then output a random one with the highest price. (several will have the same price)
I've had a look at other stackoverflow questions and found people with answers saying that if two results are the same you cannot guarantee which one will be outputted however that sounds like a bit of a glitch/hack, is there anyway to order a table by the highest results and then chose a random one of those results?
$qry="SELECT * FROM campaignInformation ORDER BY campaignInformation.bidPerCustomer DESC LIMIT 1";
two of my "bidPerCustomers" are 0.25 and I would like to to chose a random one of these every time, however not choose one with a bet of 0.11 for example
Thanks in advance guys!
I'm asumming that I will have to make a query and then choose a random one from the results however it would be nice if I could do it in the query to begin with.
If you just want to select any from those with max value, then you can build it up cleanly:
SELECT * FROM campaignInformation C WHERE C.bidPerCustomer = (
SELECT MAX(D.bidPerCustomer) FROM campaignInformation D
)
That'll net you all rows that have max value. You can then select one from that table, LIMIT 1, order by RAND()
SELECT * FROM (
SELECT * FROM campaignInformation C WHERE C.bidPerCustomer = (
SELECT MAX(D.bidPerCustomer) FROM campaignInformation D
)
) AS X
ORDER BY RAND()
LIMIT 1
Every derived table needs an alias, hence the 'AS X'
Make sure you have an index on your bidPerCustomer column, or havoc ensues.

Only return rows when there is only one value for a given column

I have a rather complex join query, whose results I only care about when there is a single distinct Table_ID value in the result. For example, if there were multiple values for Table_ID, say 1 and 2.. I would want 0 rows returned.
I was thinking of doing this by adding WHERE COUNT(DISTINCT Table_ID) = 1. Is that the best way to go about this? Doing this through LIMIT doesn't seem possible because that would limit the number of rows I get returned from other tables beyond the one I intend to limit.
Using PHP/MySQL.
I did this once by grouping on the Table_ID and then counting the number of items in the group. Something like:
SELECT *, COUNT(*) AS num FROM `myTable` GROUP BY `Table_ID` HAVING num = 1
More info: http://www.java2s.com/Code/SQL/Select-Clause/UseCOUNTGROUPandHAVING.htm

A function that randomly selects a row from the database!

I am creating an online store website that needs the functionality to select a random product from the database.
The idea is that there will be an advert for a random product that is different each time the webpage loads!
Using PHP, how would I go about doing this?
tbl_products
id
code
title
stock
cost
rrp
These are the rows I need to get access to from the database.
Thanks
A most straightforward solution would be this:
SELECT *
FROM tbl_products
ORDER BY
RAND()
LIMIT 1
However, this becomes less efficient as the number of products grows.
This solution:
Selecting random rows
is more efficient, though it still requires a full table scan.
If you product ids are distributes more or less uniformly, use this:
SELECT p.*
FROM (
SELECT
(
(
SELECT MAX(id)
FROM tbl_products
) -
(
SELECT MIN(id)
FROM tbl_products
)
) * RAND() AS rnd
) q
JOIN tbl_products p
ON id >= rnd
ORDER BY
id
LIMIT 1;
If you have gaps between ids, the products after large gaps will tend to be selected more often.
Instead of id, you may use a special unique column for this purpose which you should fill without gaps in a cron job.
ORDER BY RAND() is a well-known solution that has well-known problems.
If the product ids are a consecutive range of integers and there is a non-trivial number of rows, then it will much better to SELECT MAX(id) FROM products, generate a number of random integers between 1 and the result in PHP, and do SELECT * FROM products WHERE id IN (x, y, z) as a second query. If the ids are almost, but not quite, consecutive, you can adapt this solution to generate more random ids than needed to account for the fact that not all of them might be valid (the more fragmentation there is among ids, the more surplus numbers you should generate).
If the above is not an option, then querying like this will still be better than a pure ORDER BY RAND().
Here's a PHP solution
$range_res = mysql_query( " SELECT MAX(id) AS max_id , MIN(id) AS min_id FROM products ");
$range_row = mysql_fetch_object( $range_res );
$random = mt_rand( $range_row->min_id , $range_row->max_id );
$res = mysql_query( " SELECT * FROM products WHERE id >= $random LIMIT 0,1 ");

Counting MySQL records with a LIMIT

As I am trying to count the number of records in a table, even when the SQL statement has a LIMIT into it, overall it works, however something weird happens, the code:
$sql = "SELECT COUNT(*) AS count FROM posts
ORDER BY post_date DESC
LIMIT 5";
// ... mysql_query, etc
while($row = mysql_fetch_array($result))
{
// ... HTML elements, etc
echo $row['post_title'];
// ... HTML elements, etc
echo $row['count']; // this displays the number of posts (which shows "12").
}
Although, when displaying through the while loop, it displays this:
Notice: Undefined index: post_title in /Applications/MAMP/htdocs/blog/index.php on line 55
If I remove the COUNT(*) AS count, everything will display perfectly... how come it's doing this?
Don't use COUNT(*) to count the number of rows (for a lot of reasons). Write out your full query, and add SQL_CALC_FOUND_ROWS right after SELECT:
SELECT SQL_CALC_FOUND_ROWS id, title FROM foo LIMIT 5;
Then, after that query executed (right after), run:
SELECT FOUND_ROWS();
That will return the number of rows the original SELECT would have returned if you didn't have the LIMIT on the end (accounting for all joins and where clauses).
It's not portable, but it's very efficient (and IMHO the right way of handling this type of problem).
LIMIT does not do anything here because you're selecting a single scalar. The error is shown because you are not selecting the post title, so it is not in the $row hash.
This is happening because COUNT() is an aggregate function. You will have to do two separate queries in order to get both the count of rows in the table and separate records.
I had the same problem and found this article: http://www.mysqldiary.com/limited-select-count/
best way (especially for big tables) is using it like this:
SELECT COUNT(*) AS count FROM (SELECT 1 FROM posts
ORDER BY post_date DESC
LIMIT 5) t
now it returns a number between 0 and 5
You're asking the SELECT statement to return only COUNT(*) AS count. If you want more columns returned, you have to specify them in the SELECT statement.
You're mixing up an aggregate function COUNT() with a standard selection. You can't get an accurate post title without a GROUP BY clause in your aggregate query. The easiest thing you should do is to do this two queries - one for your count, the other for your post information. Also, there's no sense in using LIMIT on an aggregate function with no other columns in your (omitted) GROUP BY - the current query will always return one row.
What everyone is trying to say is that you should opt to use 2 separate queries instead of 1 single one.
1) get row count of table
$sql = "SELECT COUNT(*) AS count FROM posts;
2) get last 5 rows of table
$sql = "SELECT * FROM posts
ORDER BY post_date DESC
LIMIT 5";
By including COUNT(*) AS count you've removed the actual columns that you want to get the information from. Try using
SELECT *, COUNT(*) AS count FROM posts ORDER BY post_date DESC LIMIT 5
That query will accomplish both things you're trying to do in one query, but really, these should be broken out into 2 separate queries. What is the overall purpose for having a COUNT in the query? It should be done a different way.
This works for me:
$sql = "
SELECT COUNT( po.id ) AS count, p.post_title
FROM posts p
JOIN posts po
GROUP BY p.post_title
ORDER BY p.post_date DESC
LIMIT 5
";
Important is to JOIN the same table, but name the table differently. Do not forget GROUP BY, must be used.

Categories