Query using RAND but following a defined structure - mysql

I have the following problem and I would like to know how to solve it creating a query on MySQL.
Check out those two tables:
I need to follow a structure to show the results I want. It is like a randon inside a randon. For example, I want to randomize each section, but ids 1 to 3 must be together and then randomize too.
How would be a query to get such results?

With this query:
select id, id_start, id_end, rand() rnd
from table2
group by id, id_start, id_end
you can return a random number for each of the rows of table2.
Join this query to table1 and sort the result first by that random number and then by random:
select t1.id, t1.description
from table1 t1
inner join (
select id, id_start, id_end, rand() rnd
from table2
group by id, id_start, id_end
) t2
on t1.id between t2.id_start and t2.id_end
order by t2.rnd, rand()
See the demo.

Related

Create a new variable in SQL by groupby

I have 2 sql table as follows:
First table t1:
Second table t2:
I need to calculate the count of "Number" column based on "Name" column from t1 and merge it with t2.
I wrote following code. But it seems not working
select *
from (
select Name, count(Number) as count
from t1
group by Name ) as a
join ( select *
from t2 ) as b
on a.Name = b.Name;
Can any one figure out what is wrong ? Thank you very much
I think you want to use SUM() instead of COUNT().
Because SUM() sums some integers, while COUNT() counts number of occurencies.
And as also stated in the comments, multiple columns with same names will create conflicts, so you have to select the wanted columns explicit (that is usually a good idea anyway).
You could obtain your wanted endgoal by this query:
select
SUM(Number),
t1.Name,
(select val1 FROM t2 WHERE t2.Name = t1.Name LIMIT 1) as val1
FROM t1
GROUP BY t1.Name
Example in sqlfiddle: http://sqlfiddle.com/#!9/04dddf/7

Select Distinct between two tables inner join

I have table 1 which contains unique values and table 2 which contains multiple values for the same email. What I want to do is select the first value of 'id' - table 2 contains a number of ids and matching emails
SELECT DISTINCT
table1.email,
table2.id FROM
table1
INNER JOIN users ON table1.email = table2.Email
the problem is the output needs to be unique - i.e. one ID - the first one from table2 that is associated with a given email - currently we're getting multiple results - no unique or distinct values.
Probably
any id - add ORDER BY RAND()
1 row of result - add LIMIT 1.
So, the query might be something like this:
SELECT DISTINCT
table1.email,
table2.id
FROM table1
INNER JOIN table2 ON table1.email = table2.email
ORDER BY RAND()
LIMIT 1
Based on new information, it seems like you're looking for something like this instead:
Note: Works on MySQL v8+ and MariaDB 10.2+ that have window function:
SELECT email, id
FROM
(SELECT table1.email,
table2.id,
ROW_NUMBER()
OVER
(PARTITION BY table1.email ORDER BY table2.id) AS 'RowNumber'
FROM table1
INNER JOIN table2 ON table1.email = table2.email) t
WHERE RowNumber=1;
Assign ROW_NUMBER() with table1.email as partition and sort by table2.id ascending (note that the default sorting of ORDER BY is ascending so there's no need to define it as ORDER BY xxx ASC).
Turn the base query into a subquery then do a SELECT .. with condition of WHERE RowNumber=1. Hence, it will return only a single row for each email.
Alternatively, depending on your data, you could just simply do something like this:
SELECT table1.email,
MIN(table2.id) AS minID
FROM table1
INNER JOIN table2 ON table1.email = table2.email
GROUP BY table1.email;
Demo fiddle

mysql-select a random row from each id

I have a table in my db which has 2 columns: id and color. each id may have multiple rows with different values for color. so for example:
id color
--------------
1 black
1 white
1 green
2 yellow
3 red
3 black
I want to select only one row for each id, but randomly. I have already tried to use two select queries, but it always returns the first row of each id. what is the problem?!
SELECT * FROM (SELECT * FROM collections ORDER BY RAND()) AS a
GROUP BY id
You can try:
select t.*
from t
where t.color = (select t2.color
from t t2
where t2.id = t.id
order by rand()
limit 1
);
For performance, you can try an index on (id, color).
Your code should simply not work. It uses select * with group by -- meaning that you have unaggregated columns. That should be a compile-time error.
EDIT:
LOL. Of course, the above has an issue. The subquery gets called for each row, giving each row an opportunity to be in the result set. Sigh. Sometimes code doesn't do what I want it to do. One solution is to seed the random number generator. This is "arbitrary" but not "random" -- you'll get the same values on each run:
select t.*
from t
where t.color = (select t2.color
from t t2
where t2.id = t.id
order by rand(concat(t2.id, t2.color))
limit 1
);
If you don't have too many colors, you can use a group_concat() trick:
select t.id,
substring_index(group_concat(color order by rand()), ',', 1)
from tA quick and dirty solution is to seed the random number generator:
group by id;

why the sql correct and the inner mechanism for run it?

the sql as follows come from mysql document. it is:
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
The document say It finds all rows in table t1 containing a value that occurs twice in a given column , and doesnot explain the sql.
t1 and t is the same table, so the
count(*) in subquery == select count(*) from t
, isn't it?
count(*) in subquery == select count(*) from t
is wrong. because in mysql you can't use it like that. so you have to run it like that to get result of same id having two rows.
if you want to get count of same occurrence,
SELECT id, name, count(*) AS all_count FROM t1 GROUP BY id HAVING all_count > 1 ORDER BY all_count DESC
And also you can get values as your query like this as well,
select * from t1 where id in ( select id from t1 group by id having count(*) > 1 )
The query contains a correlated subquery in WHERE clause:
SELECT COUNT(*) FROM t1 WHERE t1.id = t.id
It is called correlated because it is related to the main query via t.id. So, this subquery counts the number of records having an id value that is equal to the current id value of the record returned by the main query.
Thus, predicate
(SELECT COUNT(*) FROM t1 WHERE t1.id = t.id) = 2
evaluates to true for any row with an id value that occurs twice in the table.
SELECT * FROM t1 AS t
WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
This query goes through each record in t1 and then in the subquery looks into t1 again to see if in this case id is found 2 times (and only 2 times). You can do the same for any other column in t1 (or any table for that matter).
When you would like to see all values that are multiple times in the table, change WHERE 2 = by WHERE 1 <. This will also give you the values that are 3 times, 4 times, etc. in the table.
{
SELECT id,count( * )
FROM
MyTable
group by id
having count( * )>1
}
with this code, you can see the rows which repet more than one,
and you can change this query by yourself
How about using GROUP BY and HAVING:
SELECT id, count(1) as Total FROM MyTable AS t1
GROUP BY t1.id
HAVING Total = 2

Using MYSQL GROUP_CONCAT with sub query

I am trying to get my head around using GROUP_CONCAT within MYSQL.
Basically I have the following table, table1:
id, field1, field2, active
I want to bring back 5 rows within the table but in random order. So I'm using this:
SELECT GROUP_CONCAT(id ORDER BY rand()) FROM table1 WHERE active=1
This behaves as I would expect. I then want to use the output to select the other columns (field1, field2) from the table and display the results.
So I've tried using:
SELECT *
FROM table1
WHERE id IN
(
SELECT GROUP_CONCAT(id ORDER BY rand()) as id FROM table1 WHERE active=1
);
I expected something like the above to work but I cant figure out why it doesn't. It DOES bring back results but not all of them, (i.e.) my table contains 10 rows. 6 rows are set to active=1. Therefore I would expect 6 rows to be returned ... this isn't happening I may get 1,2 or 0.
Additionally if it helps I'd like to limit the number of results returned by the sub-query to 3 but adding LIMIT doesn't seem to have any affect on the results returned.
Thank you in advance for your help
I think this is what you are looking for. This will bring back 5 random active rows.
SELECT *
FROM table1
WHERE active=1
ORDER BY RAND()
LIMIT 5;
why not use this :
SELECT *, GROUP_CONCAT(id ORDER BY rand()) as randoms FROM table1 WHERE active=1
If I understand correctly, you are trying to build a query like this:
select *
from table1
where id in (1,2,3,4,5) -- Just an example
and you are trying to "fill" the in condition with a group_concat() result.
That's not the way to do it.
You only need to specify the subquery in the parenthesis:
select *
from table1
where id in (select id from table1 where active=1)
Notice some additional things:
The order by rand() is irrelevant, because the in () will be evaluated regardless of the order of the values.
In this particular scenario, I would recommend to use a join instead of in.
Using join:
select t1.*
from
table1 as t1
inner join table1 as t2 on t1.id = t2.id
where t2.active=1