I am struggling to find an optimal solution for the following problem.
Suppose I have a table 'Table' like this:
id name report_id
1 name1 1
2 name2 3
3 name3 5
4 name1 7
5 name3 8
....................
I want to select for each value in a set: ('name1', 'name2') 10 random unique rows.
Of course it is possible to do with union like:
(SELECT * FROM Table
WHERE
name='name1'
ORDER BY RAND() LIMIT 10)
UNION
(SELECT * FROM Table
WHERE
name='name2'
ORDER BY RAND() LIMIT 10)
But if I have 100 unique names for which I have to select 10 random records - this query is going to be a bit large.
SQLFiddle demo
select ID,NAME,REPORT_ID
from
(
select *, #row:=if(name=#name,#row,0)+1 as rn, #name:=name from
(select *,RAND() as trand from t) t1,
(select #row:=0,#name:='') tm2
order by name,trand
) t2
where rn<=10
Try this:
SELECT
id,
name,
report_id
FROM
(
SELECT id,
report_id,
name,
CASE WHEN #name != name THEN #rn := 1 ELSE #rn := #rn + 1 END rn,
#name:=name
FROM (SELECT * FROM tbl ORDER BY RAND()) a,
(SELECT #rn:=0, #name := NULL) r
ORDER BY name
) s
WHERE rn <= 10;
SQL FIDDLE DEMO
This doesn't work in MySQL, but in PostgreSQL you can use partition by
select name,report_id from
(select name,report_id,row_number()
over
(partition by name order by random())
as rn from Table) a
where rn<=10
I had this same question and found this answer from a colleague.
Related
user_id | date | point
1 20 4
2 20 3
3 20 2
1 21 1
2 21 3
3 21 5
1 23 2
2 23 4
3 23 5
And query:
SELECT user_id, SUM(point) AS point, #row:=#row+1 rank FROM users GROUP BY user_id
How to show rank in this query ?
first you need to delcare #row as variable first
Something like set #row=0; select user_id,SUM(point) as point,#row := #row + 1 as rank from users GROUP BY user_id order by SUM(point) desc;
try this
SET #row=0;
SELECT user_id, SUM(point) AS point, #row:=#row+1 rank FROM users GROUP BY user_id
You can work around the declaring part using this way:
SELECT user_id, SUM(point) AS point, #row:=#row+1 rank FROM users, (SELECT #row := 0) r GROUP BY user_id
I guess you've to write it like:
SELECT user_id, SUM(point) AS point, #row:=#row+1 AS rank FROM users GROUP BY user_id JOIN (SELECT #row := 0) r;
Try this..
SELECT user_id,points, #row:=#row+1 AS Row
from (
SELECT user_id,
SUM(point) AS points rank
FROM users
GROUP BY user_id
Sort by points);
Should have an AS to alias #row to rank, and an order by on point to get them in the right order to rank:-
SELECT user_id, SUM(point) AS point, #row:=#row+1 AS rank
FROM users
CROSS JOIN (SELECT #row:=0) Sub1
GROUP BY user_id
ORDER BY point DESC
I want to get count of a row it exists in table.
+---+----+
|id |name|
+---+----+
|100|a |
+---+----+
|201|b |
+---+----+
|302|c |
+---+----+
|403|d |
+---+----+
|504|e |
+---+----+
In the above table i want to get output as 4(i.e) the count of that row exists. I have 'd' value and have to write a query to get the output as 4 where name = d
I think code will be something like the below,
select count(*) ......
If i'm correctly understand you this query is what you want:
set #row_number = 0;
select #row_number := #row_number + 1 as row_number,name FROM table_name;
SELECT ROW_NUMBER() OVER(ORDER BY id) FROM yourtable WHERE name='d'
MySQL version
SET #rank=0;
SELECT #rank := #rank+1 AS rank
FROM yourtable WHERE name='d'
ORDER BY id asc
#vinoth I think #Pragmatist Answer would work for you. Just add this clause to his query :
set #row_number = 0;
select #row_number := #row_number + 1 as row_number,name FROM table_name Where name='b';
Try the below. MS SQL is a tested query, i just converted into mysql. Hope you can modify as per your requirement.
SET #rank=0;
SELECT * FROM Table1 T1
INNER JOIN(
SELECT #rank := #rank+1 AS rank, ID
FROM Table1
ORDER BY id asc) temp ON temp.ID = T1.ID
WHERE T1.name = 'd'
MS SQL Query will be
SELECT * FROM Table1 T1
INNER JOIN(SELECT id, ROW_NUMBER() OVER (Order by id) AS RowNumber from Table1) temp ON temp.ID = T1.ID
WHERE T1.name = 'd'
To get the Row Number
SELECT ROW_NUMBER() OVER(ORDER BY id) from table WHERE name='d'
To get the row count with your condition use below query
select count(*) as count from table where name = 'b'
for example:
my products best sort string is "'8207,17631,16717,18545,9062,17469,17246,17750"
this string is posted from php , I dont want to store them in datebase. I want to query datas from mysql and left join a temp table then sort by the temp table'sort.
how can I get this temp table from a string ?
my codes seems will be like that bellow:(wrong codes)
select
p.products_id
from
(
select '18207,17631,16717,18545,9062,17469,17246,17750' as products_id
) as p
order by p.sort
Your best approach could be - to use UNION for generating row set from string. This, however, will require joining your string in your application, like this:
$string = '18207,17631,16717,18545,9062,17469,17246,17750';
$id = 0;
$sql = join(' UNION ALL '.PHP_EOL, array_map(function($item) use (&$id)
{
return 'SELECT '.(++$id).' AS sort, "'.$item.'" AS products_id';
}, explode(',', $string)));
-end result will be like:
SELECT 1 AS sort, "18207" AS products_id UNION ALL
SELECT 2 AS sort, "17631" AS products_id UNION ALL
SELECT 3 AS sort, "16717" AS products_id UNION ALL
SELECT 4 AS sort, "18545" AS products_id UNION ALL
SELECT 5 AS sort, "9062" AS products_id UNION ALL
SELECT 6 AS sort, "17469" AS products_id UNION ALL
SELECT 7 AS sort, "17246" AS products_id UNION ALL
SELECT 8 AS sort, "17750" AS products_id
However, if you want to do that in SQL - that will not be easy, since MySQL doesn't supports sequences - and, therefore, you'll need to use some tricks to produce desired rows set. There's a way to generate N consecutive numbers with:
SELECT id+1
FROM
(SELECT
(two_1.id + two_2.id + two_4.id +
two_8.id + two_16.id) AS id
FROM
(SELECT 0 AS id UNION ALL SELECT 1 AS id) AS two_1
CROSS JOIN (SELECT 0 id UNION ALL SELECT 2 id) AS two_2
CROSS JOIN (SELECT 0 id UNION ALL SELECT 4 id) AS two_4
CROSS JOIN (SELECT 0 id UNION ALL SELECT 8 id) AS two_8
CROSS JOIN (SELECT 0 id UNION ALL SELECT 16 id) AS two_16
) AS init
LIMIT 10
-this will result in 10 numbers 1..10 (check this fiddle). Using this, you can get your end result:
SELECT
ELT(id+1, 18207,17631,16717,18545,9062,17469,17246,17750) AS products_id,
id+1 AS sort
FROM
(SELECT
(two_1.id + two_2.id + two_4.id +
two_8.id + two_16.id) AS id
FROM
(SELECT 0 AS id UNION ALL SELECT 1 AS id) AS two_1
CROSS JOIN (SELECT 0 id UNION ALL SELECT 2 id) AS two_2
CROSS JOIN (SELECT 0 id UNION ALL SELECT 4 id) AS two_4
CROSS JOIN (SELECT 0 id UNION ALL SELECT 8 id) AS two_8
CROSS JOIN (SELECT 0 id UNION ALL SELECT 16 id) AS two_16
) AS init
HAVING
products_id IS NOT NULL
-check this fiddle. However, this may be slow and I recommend you to use your application layer to build desired SQL.
something like this? use UNION to generate inline view. this can be generated by Client side.
SELECT *
FROM
(
SELECT '18207' AS products_id, 1 as sort
UNION
SELECT '17631' AS products_id, 2 as sort
UNION
SELECT '16717' AS products_id, 3 as sort
UNION
SELECT '18545' AS products_id, 4 as sort
UNION
SELECT '9062' AS products_id, 5 as sort
) x JOIN tbl x.products_id = tbl.products_id
ORDER BY sort
I found some good answers for this question, but I can't really get them to work.
I wan't to get a players rank from a hiscore table.
id name score
1 John 10
2 Linda 5
3 Emmy 25
I want to pass in a name in the query (Linda) and get her rank (She only have 5 points in the table above), and get her rank (nr 3).
I found a similar question with this answer, but don't understand it:
SELECT uo.*,
(
SELECT COUNT(*)
FROM users ui
WHERE (ui.points, ui.id) >= (uo.points, uo.id)
) AS rank
FROM users uo
WHERE id = #id
Thanks in advance
SELECT (COUNT(*) + 1) AS rank FROM hiscore WHERE score > (SELECT score FROM hiscore WHERE name = 'Linda')
Try this query -
SELECT name, score, rank FROM
(SELECT *, #r:=#r + 1 rank FROM table_name ORDER BY score DESC) t1,
(SELECT #r:=0) t2
WHERE name = 'Linda'
SET #rownum := 0;
SELECT rank, name, score
FROM
(SELECT #rownum := #rownum + 1 AS rank, name, score
FROM players
ORDER BY score DESC)
Here is my query:
SELECT * FROM Photos WHERE Event_ID IN ($eventidstring)
I know I can limit the total amount of results from this query using LIMIT 5
I need the Limit the amount of results Per value in $eventidstring.
So if $eventidstring = 23,41,23*
*And there are 10 results WHERE Event_ID = 23, I want to limit this amount to 5. The same for all the other values in $eventidstring.
You may have some joy doing something similar to Oracle's RANK by PARITION in MySQL.
Sadly this feature is not available in MySQL though you can work around it using this method
Dump that in an inline view and then select those rows with rank <= 5;
Hence:
SELECT t.* FROM (
SELECT (
CASE Event_id
WHEN #curEventId
THEN #curRow := #curRow + 1
ELSE #curRow := 1 AND #curEventId := Event_Id END
) AS rank,
p.*
FROM Photos p INNER JOIN (SELECT #curRow := 0, #curEventId := '') r
ORDER BY p.Event_Id DESC
) t
WHERE t.rank <= 5 ORDER BY t.Event_Id asc;
Consider how you are going to 'choose' the top five by Event_Id too. You can always add in more after the ORDER BY p.Event_Id DESC to decide this.
I take it you're writing that query somewhere inside your PHP, so you need to split the $eventidstring into it's component values, form a SELECT for each and UNION all after the first one.
You sould do this with a loop of some sort, and concatenate the query strings in the loop...
If I understand correctly and you want to get five of each, you can use this:
(SELECT * FROM Photos WHERE Event_ID = 23 LIMIT 5)
UNION
(SELECT * FROM Photos WHERE Event_ID = 41 LIMIT 5)
UNION
(SELECT * FROM Photos WHERE Event_ID = ... LIMIT 5)
...
Maybe with a SELECT UNION but you need a new select for each value:
SELECT * FROM Photos WHERE Event_ID = 23 LIMIT 5
UNION SELECT * FROM Photos WHERE Event_ID = 41 LIMIT 5
UNION SELECT ...