I have a sample code
products(id, name)
1 | Apple
2 | Sony
3 | Nokia
4 | Samsung
5 | LG
6 | Motorola
7 | Ekricson
And mysql:
SELECT id, name FROM `products` AS prod
ORDER BY RAND(prod.id) LIMIT 5
When i run code is result is:
4 | ...
7 | ...
1 | ...
5 | ...
6 | ...
But next ... is result is:
4 | ...
7 | ...
1 | ...
5 | ...
6 | ...
Id not change when run random, how to fix ix
You should use ORDER BY RAND() and not ORDER BY RAND(prod.product_id)
From RAND manual:
RAND(), RAND(N)
Returns a random floating-point value v in the range 0 <= v < 1.0.
If a constant integer argument N is specified, it is used as the seed value
which produces a repeatable sequence of column values.
The argument inside the RAND(x) function is the seed, so you're seeding it with the same value every time. Instead, leave it as RAND() and it will be different.
SELECT id, name FROM products AS prod
ORDER BY RAND() LIMIT 5
You probably want just ORDER BY RAND() rather than ORDER BY RAND(prod.id) -- if you give RAND() an integer argument, it's used as the seed value, so you will always get the same "random" value back.
See http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand for the details.
Use this way:
SELECT id, name FROM `products` AS prod
ORDER BY RAND() LIMIT 5;
See manual here
Related
In one of my recent PHP (CodeIgniter) based projects, a MySQL table contains almost 30.000 records (and will increase more). If I show those records as a list, the performance is reduced (MySQL retrieves all of those records in a quick time, but running a PHP loop for around 30.000 times is not feasible). So my plan is to load 100 records at a time and create a pagination so that the user can select a page number to load that specified number of records.
I can load the first 100 records easily using the following query:
SELECT * FROM <table_name> ORDER BY id ASC LIMIT 100
But the problem is: when I select page=2, page=3, ...., page=n. How can I write a MySQL query that will load 2nd 100 records (for page=2), 3rd 100 records (for page=3),... ... nth 100 record (for page=n)?
N.B: Please refer the 101 number record may not have the id 101, similar 201 number record may not have the id of 201, so please don't suggest me a query that will depend on Primary Key
Can anyone help me to find out the correct query?
Thanks
first hundred
SELECT * FROM <table_name> ORDER BY id ASC LIMIT 0, 100
next hundred
SELECT * FROM <table_name> ORDER BY id ASC LIMIT 100, 100
you're very observant about putting the order by in
THE LIMIT STATEMENT EXPLAINED:
The LIMIT statement is NOT a WHERE clause. It does not select by id nor in fact by any criteria, (there where clause does that) Instead the limit clause simply ensures that you are returned a piece of the block of results that are subset of "everything". Hence why it is important to mention an order by each time, so that each subsequent call will give you the correct piece of the data block in order, and you can 'next', 'next', 'next' through them
EG: for the disordered table this_table:
+-------+-------------+
| id | value |
+-------+-------------+
| 1 | bob |
| 12 | fish |
| 112 | pink |
| 2 | cat |
| 8 | dog |
| 56 | blue |
| 88 | grey |
| 87 | red |
+-------+-------------+
the selects return as below:
SELECT * FROM <this_table> ORDER BY id ASC LIMIT 0,5
+-------+-------------+
| id | value |
+-------+-------------+
| 1 | bob |
| 2 | cat |
| 8 | dog |
| 12 | fish |
| 56 | blue |
+-------+-------------+
and
SELECT * FROM <this_table> ORDER BY id ASC LIMIT 5,5
+-------+-------------+
| id | value |
+-------+-------------+
| 87 | red |
| 88 | grey |
| 112 | pink |
+-------+-------------+
notice the lack of rows 9 and 10 this is deliberate and shows MySQL working as intended
incidentally you should also look at adding an index on id this will MASSIVELY increase the speed of these selects
ALTER TABLE <table_name> ADD INDEX `id` (`id`)
try this
SELECT * FROM <table_name> ORDER BY id ASC LIMIT <p * 100>, 100
so u must have
SELECT * FROM <table_name> ORDER BY id ASC LIMIT 0, 100
SELECT * FROM <table_name> ORDER BY id ASC LIMIT 100, 100
this work if first page = 0, else, u need (p-1) * 100
https://www.w3schools.com/php/php_mysql_select_limit.asp
I am trying to get a certain amount of rows of which another amount of rows satisfy a specific condition.
I'll explain.
table 1:
ID | NAME
1 | Thomas
2 | Jason
3 | Oleg
4 | Matt
5 | Sheldon
6 | Jenny
table 2:
ID | ACTIVE
1 | 1
2 | 0
3 | 1
4 | 1
5 | 0
6 | 1
Query:
SELECT tbl_1.ID, tbl_1.NAME, tbl_2.ACTIVE
FROM tbl_1 JOIN tbl_2 ON
tbl_1.ID = tbl_2.ID
WHERE tbl_2.ACTIVE=1
LIMIT 5
in this example I would like to get a minimum number of 5 users, of which 3 are active.
of course the query above will not do the job right, as it limits the total rows to 5. But 3 of the rows in the result (or less if no more exist) MUST be active.
the other way I can think of getting this done, is a union, but my query is so cumbersome, long and complex.
Any ideas?
Use ORDER BY instead:
SELECT tbl_1.ID, tbl_1.NAME, tbl_2.ACTIVE
FROM tbl_1 JOIN
tbl_2
ON tbl_1.ID = tbl_2.ID
ORDER BY (tbl_2.ACTIVE = 1) DESC
LIMIT 5;
This puts the active users at the top of the list and then fills in the rest with other users.
Note: The ORDER BY clause could simply be ORDER BY tbl_2.ACTIVE DESC. I left the boolean logic so you could see the similarity to the WHERE clause.
The way to at least x results is to use the count aggregate and the keyword having
select f1, count(*) records
from yourTable
where whatever
group by f1
having count(*) > x
This question already has answers here:
mysql unique number generation
(9 answers)
Closed 8 years ago.
I am wondering if there is any way to generate the random five digit number and insert into database using mysql. I know i can do it using PHP but wanted to know if i can get rid of the php and do it using database. Also, the generated number should be different than the numbers already stored in the database.
Following is example as how it should look like:
I have four letters of pattern common in random_no field which is org1 and want to append other 5 random letters as shown in following example:
+-------+-----------+-----------+--------------------------------------------+
| id | title | phone | ABN | Random No |
+-------+-----------+----------+---------------------------------------------
| 1 | title1 | 4765 5678 | 214-444-1234 | org123456 |
| 2 | title2 | 4444 4444 | 555-111-1234 | org109876 |
| 3 | title3 | 3333 3333 | 214-222-1234 | org187654 |
| 4 | title4 | 1111 1111 | 817-333-1234 | org156432 |
| 5 | title5 | 2222 2222 | 214-555-1234 | org177654 |
+-------+-----------+-----------+--------------------------------------------
Any help will be appreciated.
Now there is no guarentee that there are not going to be duplicates... but this is getting two random numbers and multiplying them by different numbers so its not all that likely that they will be getting random numbers
UPDATE table t,
( SELECT id, LPAD(FLOOR(7 + (RAND() * 50) * (RAND() * 333)), 5, 0) as join_num
FROM table
)t1
SET t.random_no = CONCAT(t.random_no, t1.join_num)
WHERE t.id = t1.id;
From here I recommend you do this.. after updating your table go back through and run this query
SELECT id FROM table
GROUP BY random_no
HAVING COUNT(*) > 1;
if there are any results returned then the id's there will need a different random number and you can just change it at any duplicate spots once you know if there are any dupes
Breakdown of the update query....
update the table alias t.
select from table the id and then the random number alias t1.
concat the number and the column by row..
where the id's are equal... getting a different number for each row.
LPAD is a zero fill so that way if the number is smaller than 5 spaces it'll fill it in with 0's and then you have to use FLOOR() with RAND() for the random number.
Hope thats helpful!
I have a table with scores like this:
score | user
-------------------
2 | Mark
4 | Alex
3 | John
2 | Elliot
10 | Joe
5 | Dude
The table is gigantic in reality and the real scores goes from 1 to 25.
I need this:
range | counts
-------------------
1-2 | 2
3-4 | 2
5-6 | 1
7-8 | 0
9-10 | 1
I've found some MySQL solutions but they seemed to be pretty complex some of them even suggested UNION but performance is very important. As mentioned, the table is huge.
So I thought why don't you simply have a query like this:
SELECT COUNT(*) as counts FROM score_table GROUP BY score
I get this:
score | counts
-------------------
1 | 0
2 | 2
3 | 1
4 | 1
5 | 1
6 | 0
7 | 0
8 | 0
9 | 0
10 | 1
And then with PHP, sum the count of scores of the specific ranges?
Is this even worse for performance or is there a simple solution that I am missing?
Or you could probaly even make a JavaScript solution...
Your solution:
SELECT score, COUNT(*) as counts
FROM score_table
GROUP BY score
ORDER BY score;
However, this will not returns values of 0 for count. Assuming you have examples for all scores, then the full list of scores is not an issue. You just won't get counts of zero.
You can do what you want with something like:
select (case when score between 1 and 2 then '1-2'
when score between 3 and 4 then '3-4'
. . .
end) as scorerange, count(*) as count
from score_table
group by scorerange
order by min(score);
There is no reason to do additional processing in php. This type of query is quite typical for SQL.
EDIT:
According to the MySQL documentation, you can use a column alias in the group by. Here is the exact quote:
An alias can be used in a query select list to give a column a
different name. You can use the alias in GROUP BY, ORDER BY, or HAVING
clauses to refer to the column:
SELECT
SUM(
CASE
WHEN score between 1 and 2
THEN ...
Honestly, I can't tell you if this is faster than passing "SELECT COUNT(*) as counts FROM score_table GROUP BY score" into PHP and letting PHP handle it...but it add a level of flexibility to your setup. Create a three column table as 'group_ID', 'score','range'. insert values into it to get your groupings right
1,1,1-2
1,2,1-2
1,3,3-4
1,4,3-4
etc...
Join to it on score, group by range. THe addition of the 'group_ID' allows you to set groups...maybe have group 1 break it into groups of two, and let a group_ID = 2 be a 5 set range (or whatever you might want).
I find the table use like this is decently fast, requires little code changing, and can readily be added to if you require additional groupings or if the groupings change (if you do the groupings in code, the entire case section needs to be redone to change the groupings slightly).
How about this:
select concat((score + (1 * (score mod 2)))-1,'-',(score + (1 * (score mod 2)))) as score, count(*) from TBL1 group by (score + (1 * (score mod 2)))
You can see it working in this fiddle: http://sqlfiddle.com/#!2/215839/6
For the input
score | user
-------------------
2 | Mark
4 | Alex
3 | John
2 | Elliot
10 | Joe
5 | Dude
It generates this:
range | counts
-------------------
1-2 | 2
3-4 | 2
5-6 | 1
9-10 | 1
If you want a simple solution which is very powerful, add an extra field within your table and put a value in it for the score so 1 and 2 have the value 1, 3 and 4 has 2. With that you can group by that value. Only by inserting the score you've to add an extra field. So your table looks like this:
score | user | range
--------------------------
2 | Mark | 1
4 | Alex | 2
3 | John | 2
2 | Elliot | 1
10 | Joe | 5
5 | Dude | 3
Now you can do:
select count(score),range from table group by range;
This is always faster if you've an application where selecting has prior.
By inserting do this:
$scoreRange = 2;
$range = ceil($score/$scoreRange);
Looking for a solution to keep a random order of a user table in the database when clicking the next page button.
Actually I have a database with 1000 users and I want to display 10 users each page (in a memberlist), my query looks like this:
$sql = "SELECT * FROM users ORDER BY user_id LIMIT 1,10";
Now I would like to ORDER BY RAND() and it works, except of course when clicking the next page, then it is shuffled again and it happens sometimes that the same users will be there again.
So my question is about a solution to keep the random order I had on the first page, also on the next pages.
I thought about to set a $_SESSION variable when someone visits the memberlist for the first time with shuffled numbers from 1 to 1000 in it and then order the members by position in the $_SESSION variable where a number is equal to a user_id.
Don't know how this might be possible, but I actually imagine a solution like:
$numbers = range(1, 1000);
$shuffled_numbers = shuffle($numbers);
$sort = $_SESSION['random_user_sort'] = $shuffled_numbers;
So I will have a mysql query when clicking page two (next page) like this:
$sql = "SELECT * FROM users ORDER BY $sort LIMIT 11,20";
Any solution to let it work this way or even better ideas?
The RAND() function does not really generate random numbers but what's called pseudo random numbers: numbers are calculated with a deterministic formula and they're just intended to look random. To calculate a new number, you take the previous one and apply the formula to it, and that's how we get different output with a deterministic function: by using different input.
The initial number we use is known as seed. If you have a look at the manual you'll see that RAND() has an optional argument:
RAND(), RAND(N)
Returns a random floating-point value v in the range 0 <= v < 1.0. If
a constant integer argument N is specified, it is used as the seed
value, which produces a repeatable sequence of column values
You've probably figured out by now where I want to go:
mysql> SELECT language_id, name FROM language ORDER BY RAND(33);
+-------------+----------+
| language_id | name |
+-------------+----------+
| 3 | Japanese |
| 1 | English |
| 4 | Mandarin |
| 6 | German |
| 5 | French |
| 2 | Italian |
+-------------+----------+
6 rows in set (0.00 sec)
mysql> SELECT language_id, name FROM language ORDER BY RAND(33);
+-------------+----------+
| language_id | name |
+-------------+----------+
| 3 | Japanese |
| 1 | English |
| 4 | Mandarin |
| 6 | German |
| 5 | French |
| 2 | Italian |
+-------------+----------+
6 rows in set (0.00 sec)
P.S. The manual is not explicit about the seed range (it just says integer), you might need some extra research (or just some quick testing).