Get Rank by votes and number of same rank PHP MySQL - php

i am trying to get rank and number of same rank by votes but unfortunately no success.
Here my table structure:
| ID| user_id | votes |
| --| ------- | ----- |
| 1 | D10 | 15 |
| 2 | D5 | 9 |
| 3 | D20 | 9 |
| 4 | D23 | 7 |
| 5 | D35 | 3 |
| 6 | D65 | 2 |
I need the rank of user according to votes, referring to above table i need the rank as:
| user_id | Rank|
| ------- | ----|
| D10 | 1 |
| D5 | 2 |
| D20 | 2 |
| D23 | 3 |
| D35 | 4 |
| D65 | 5 |
and also i need the number of rank, referring to above ranks i need:
Rank 1 = 1
Rank 2 = 2
Rank 3 = 1
Rank 4 = 1
rank 5 = 1
i tried to get rank :
SELECT user_id, votes, FIND_IN_SET( votes, (
SELECT GROUP_CONCAT( DISTINCT votes
ORDER BY votes DESC ) FROM table)
) AS rank
FROM votes
the above query i tried referring to this answer to get the ranks but i am getting error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use
near '( votes , (SELECT GROUP_CONCAT( DISTINCT votes ORDER BY votes DESC
)
i need the desired result using PHP and MySQL.

On MySQL 8+ you could use windows function dense_rank and count over
with votes_rank as (
select *,
dense_rank() over (order by votes desc) as rnk
from votes
) , count_rank as
( select votes_rank.*,
count(*)over (partition by rnk) as cnt
from votes_rank
) select id,
user_id,
votes,
rnk as votes_rank,
cnt as count_rank
from count_rank;
https://dbfiddle.uk/o1DiPyDz
Consider the following data,
CREATE TABLE votes (
id int,
user_id varchar(10),
votes int );
insert into votes values (1,'D10',15), (2,'D5 ',9), (3,'D20',9), (4,'D23',7), (7,'D50',7), (5,'D35',3), (6,'D65',2);
Result:
id user_id votes votes_rank count_rank
1 D10 15 1 1
2 D5 9 2 2
3 D20 9 2 2
4 D23 7 3 2
7 D50 7 3 2
5 D35 3 4 1
6 D65 2 5 1
Edit,
On MySQL version <8
select tbl.id,tbl.user_id,tbl.votes,tbl.rnk,votes_count
from (SELECT a.id,
a.user_id,
a.votes,
count(b.votes)+1 as rnk
FROM votes a
left join votes b on a.votes<b.votes
group by a.id,a.user_id,a.votes
order by a.votes desc
) as tbl
inner join (select rnk,count(rnk) as votes_count
from ( SELECT a.id,
a.user_id,
a.votes,
count(b.votes)+1 as rnk
FROM votes a
left join votes b on a.votes<b.votes
group by a.id,a.user_id,a.votes
order by a.votes desc
) a2
group by rnk
) as tbl1 on tbl1.rnk = tbl.rnk;
https://dbfiddle.uk/XlsBjrZO

Related

Stuck in building MySQL query

Given an example of table:
id | item_id | user_id | bid_price
----------------------------------
The task is to select rows with minimum bid_price for each item_id in the provided set.
For example: item_id = [1, 2, 3] - so I need to select up to three (3) rows, having a minimum bid_price.
Example of data:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
2 | 1 | 12 | 2
3 | 1 | 13 | 3
4 | 1 | 14 | 1
5 | 1 | 15 | 4
6 | 2 | 16 | 2
7 | 2 | 17 | 1
8 | 3 | 18 | 2
9 | 3 | 19 | 3
10 | 3 | 18 | 2
Expected result:
id | item_id | user_id | bid_price
----------------------------------
1 | 1 | 11 | 1
7 | 2 | 17 | 1
8 | 3 | 18 | 2
Actually, I'm using Symfony/Docine DQL, but it will be enough with a plain SQL example.
For the all the columns in the rows you could use a inner join on subselect for min bid price
select m.id, m.item_id, m.user_id, m.bid_price
from my_table m
inner join (
select item_id, min(id) min_id, min(bid_price) min_price
from my_table
where item_id IN (1,2,3)
group by item_id
) t on t.item_id = m.item_id
and t.min_price= m.bid_price
and t.min_id = m.id
or .. if you have some float data type you could use a acst for unsigned
select m.id, m.item_id, m.user_id, cast(m.bid_price as UNSIGNED)
from my_table m
inner join (
select item_id, min(id) min_id, min(bid_price) min_price
from my_table
where item_id IN (1,2,3)
group by item_id
) t on t.item_id = m.item_id
and t.min_price= m.bid_price
and t.min_id = m.id
You can use MIN() with GROUP BY in the query:
SELECT id, item_id, MIN(bid_price) AS min_bid, user_id
FROM your_tbl
GROUP BY item_id
HAVING item_id in(1, 2, 3);
Use this query:
SELECT id, item_id, user_id, min(bid_price) as bid_price
FROM YOUR_TABLE_NAME
GROUP BY item_id;

mysql count how many times the same value appears across multiple colums

during a group project we recent sent out a survey regarding the site we're building. I've put the data into a mysql database and i'm trying to figure out how to count how many times certain scores was given in each category
the table looks like this
+-----------------+--------------+-------------------+
| Design | Ease of use | Responsiveness |
+-----------------+--------------+-------------------+
| 5 | 5 | 5
| 4 | 4 | 4
| 3 | 3 | 3
| 2 | 2 | 2
| 1 | 1 | 1
| 5 | 4 | 2
| 5 | 4 | 4
| 3 | 3 | 3
| 1 | 2 | 2
| 1 | 2 | 2
I've found a query that works for one colum
SELECT Design, COUNT(*) AS num FROM table GROUP BY Design
I would then get
Design | num
-------------
5 | 3
4 | 1
3 | 2
2 | 1
1 | 3
If i were to try
SELECT Design, COUNT(*) AS num1, Ease of use, COUNT(*) as num2 FROM table
GROUP BY Design, Ease of use
The table gets totally messed up.
What I want is to get
Design | num1 | Ease of use | num2 | Responsiveness | num3
------------- --------------------------------------------------
5 | 3 | 5 | 1 | 5 | 1
4 | 1 | 4 | 3 | 4 | 2
3 | 2 | 3 | 2 | 3 | 2
2 | 1 | 2 | 3 | 2 | 4
1 | 3 | 1 | 1 | 1 | 1
Any help would be greatly appreciated
You can unpivot the values and then aggregate. In MySQL, that typically uses union all:
select val, count(*)
from ((select design as val from table) union all
(select ease_of_use from table) union all
(select responsiveness from table
) der
group by val
order by val desc;
For what you want to get, you can do:
select val, sum(design) as design, sum(ease_of_use) as ease_of_use,
sum(responsiveness) as responsiveness
from ((select design as val, 1 as design, 0 as ease_of_use, 0 as responsiveness from table) union all
(select ease_of_use, 0, 1, 0 from table) union all
(select responsiveness, 0, 0, 1 from table
) der
group by val
order by val desc;
I see no reason to repeat the value three times.
Use a synthesized table with the different values, and join this with subqueries that get the counts of each score.
SELECT nums.num AS Design, t1.count AS num1,
nums.num AS `Ease of Use`, t2.count AS num2,
nums.num AS Responsiveness, t3.count AS num3
FROM (SELECT 1 AS num UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) AS nums
LEFT JOIN (
SELECT Design, COUNT(*) AS count
FROM yourTable
GROUP BY Design) AS t1 ON t1.Design = nums.num
LEFT JOIN (
SELECT `Ease of Use`, COUNT(*) AS count
FROM yourTable
GROUP BY `Ease of Use`) AS t2 ON t2.`Ease of Use` = nums.num
LEFT JOIN (
SELECT Responsiveness, COUNT(*) AS count
FROM yourTable
GROUP BY Responsiveness) AS t3 ON t3.Responsiveness = nums.num
DEMO
Here are three ways:
select s.score,
(select count(*) from tbl where `Design` = s.score) as `Design`,
(select count(*) from tbl where `Ease of use` = s.score) as `Ease of use`,
(select count(*) from tbl where `Responsiveness` = s.score) as `Responsiveness`
from (
select Design as score from tbl
union select `Ease of use` from tbl
union select Responsiveness from tbl
) s
order by score desc
http://sqlfiddle.com/#!9/002303/2
select s.score,
(select count(*) from tbl where `Design` = s.score) as `Design`,
(select count(*) from tbl where `Ease of use` = s.score) as `Ease of use`,
(select count(*) from tbl where `Responsiveness` = s.score) as `Responsiveness`
from (select 1 as score union select 2 union select 3 union select 4 union select 5) s
order by score desc
http://sqlfiddle.com/#!9/002303/4
select s.score,
sum(`Design` = score) as `Design`,
sum(`Ease of use` = score) as `Ease of use`,
sum(`Responsiveness` = score) as `Responsiveness`
from (select 1 as score union select 2 union select 3 union select 4 union select 5) s
cross join tbl t
group by s.score
order by s.score desc
http://sqlfiddle.com/#!9/002303/5
They all return the same result:
| score | Design | Ease of use | Responsiveness |
|-------|--------|-------------|----------------|
| 5 | 3 | 1 | 1 |
| 4 | 1 | 3 | 2 |
| 3 | 2 | 2 | 2 |
| 2 | 1 | 3 | 4 |
| 1 | 3 | 1 | 1 |
As #futureweb wrote in the comment, I don't see a reason to repeat the score three times. Though you can if you want using aliases.
If you have millions of rows ;-) and no indexes you would want to get the result with only one table scan. This is possible with:
select
sum(`Design` = 1) as d1,
sum(`Design` = 2) as d2,
sum(`Design` = 3) as d3,
sum(`Design` = 4) as d4,
sum(`Design` = 5) as d5,
sum(`Ease of use` = 1) as e1,
sum(`Ease of use` = 2) as e2,
sum(`Ease of use` = 3) as e3,
sum(`Ease of use` = 4) as e4,
sum(`Ease of use` = 5) as e5,
sum(`Responsiveness` = 1) as r1,
sum(`Responsiveness` = 2) as r2,
sum(`Responsiveness` = 3) as r3,
sum(`Responsiveness` = 4) as r4,
sum(`Responsiveness` = 5) as r5
from tbl
This will return the data you need, but not in the form you'd like:
| d1 | d2 | d3 | d4 | d5 | e1 | e2 | e3 | e4 | e5 | r1 | r2 | r3 | r4 | r5 |
|----|----|----|----|----|----|----|----|----|----|----|----|----|----|----|
| 3 | 1 | 2 | 1 | 3 | 1 | 3 | 2 | 3 | 1 | 1 | 4 | 2 | 2 | 1 |
So you would need to post process it.

mysql - split columns to rows dynamically

I have the table training, I want to split Training_name Column values to multiple Rows:
SLNO Category Training_name
1 A 1,5,9,15,12,16
2 B 2,6,10,17
3 C 1,3,7,19,14,18
I used below Query but using this Query i can only split into two rows...
SELECT training.SLNO,training.CATEGORY, SubString_Index(training.TRAINING_NAME, ',', 1) AS TRAINING_NAME FROM training UNION ALL SELECT training.SLNO,training.CATEGORY, SubString_Index(training.TRAINING_NAME, ',', -1) FROM training
i am trying to get the table as given below,Please help me out
SLNO Category Training_name
1 A 1
1 A 5
1 A 9
1 A 15
1 A 12
1 A 16
2 B 2
2 B 6
2 B 10
2 B 17
3 C 1
3 C 3
3 C 7
3 C 19
3 C 14
3 C 18
DROP TABLE IF EXISTS my_bad_table;
DROP TABLE IF EXISTS my_good_table;
CREATE TABLE my_bad_table
(SLNO INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,Category CHAR(1) NOT NULL
,Training_name VARCHAR(200) NOT NULL
);
INSERT INTO my_bad_table VALUES
(1,'A','1,5,9,15,12,16'),
(2,'B','2,6,10,17'),
(3,'C','1,3,7,19,14,18');
CREATE TABLE my_good_table AS
SELECT DISTINCT x.SLNO
, x.Category
, CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(x.training_name,',',y.i+1),',',-1) AS UNSIGNED) training_name
FROM my_bad_table x
, (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5
UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 8 UNION SELECT 9) y
ORDER
BY slno
, category
, training_name;
SELECT * FROM my_good_table;
+------+----------+---------------+
| SLNO | Category | training_name |
+------+----------+---------------+
| 1 | A | 1 |
| 1 | A | 5 |
| 1 | A | 9 |
| 1 | A | 12 |
| 1 | A | 15 |
| 1 | A | 16 |
| 2 | B | 2 |
| 2 | B | 6 |
| 2 | B | 10 |
| 2 | B | 17 |
| 3 | C | 1 |
| 3 | C | 3 |
| 3 | C | 7 |
| 3 | C | 14 |
| 3 | C | 18 |
| 3 | C | 19 |
+------+----------+---------------+
If 1s are always 'A', etc, then a further step towards normalization is required to remove that redundancy.
Here is one method:
select slno, category, substring_index(training_name, ',', 1) + 0 as training_id
from t
union all
select slno, category, substring_index(substring_index(training_name, ',', 2), ',', -1) + 0 as training_id
from t
where training_name like '%,%'
union all
select slno, category, substring_index(substring_index(training_name, ',', 3), ',', -1) + 0 as training_id
from t
where training_name like concat('%', repeat(',%', 2))
union all
select slno, category, substring_index(substring_index(training_name, ',', 4), ',', -1) + 0 as training_id
from t
where training_name like concat('%', repeat(',%', 3))
union all
. . .
Repeat for as often as you need. Store the results in a new table. Fix foreign key references and other aspects of the data. Drop the original table (well, archive it) and never use that structure again.
It works to me..
SELECT DISTINCT x.PARENT_SLNO, x.TRAINING_CATEGORY, CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(x.TRAINING_NAME,',',y.i+1),',',-1) AS UNSIGNED) TRAINING_NAME FROM assessment_training x, (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 8 UNION SELECT 9) y where PARENT_SLNO = 3 and TRAINING_CATEGORY='technical' ORDER BY PARENT_SLNO,TRAINING_CATEGORY,TRAINING_NAME

mysql - Unknown column in 'IN/ALL/ANY subquery'

I have following table named 'votes', where participant's upvote(1) and downvote(-1) stores. I want to get top 3 voted participant ids and its total votes, where total vote = upvote - downvote. I wrote query as given below but getting error : "Unknown column 'total_votes' in 'IN/ALL/ANY subquery'"
table 'votes'
---------------------------------
| participant_id | vote| voter_id
+------+-------+---------+------+
| 1 | 1 | 1
| 2 | 1 | 1
| 3 | 1 | 1
| 4 | -1 | 1
| 5 | 1 | 1
| 1 | -1 | 2
| 2 | 1 | 2
| 3 | 1 | 2
| 4 | 1 | 2
| 5 | 1 | 2
| 1 | 1 | 3
| 2 | 1 | 3
| 3 | -1 | 3
| 4 | -1 | 3
+------+-------+---------+-----+
SELECT `participant_id`, SUM( `vote` ) AS total_votes FROM `votes`
WHERE total_votes IN
(SELECT total_votes FROM
(SELECT DISTINCT (SUM( vote )) AS total_votes FROM `votes` GROUP BY `participant_id`
ORDER BY `total_votes` DESC LIMIT 0 , 3) AS temp )
GROUP BY `participant_id`
Expected result would be
-------------------------------
| participant_id | total_votes
+------+-------+--------+------+
| 2 | 3
| 5 | 2
| 1 | 1
| 3 | 1
+------+-------+--------+------+
You can rewrite your query by using join to get the top participants whose vote score lies in top 3 votes i.e top 3 votes are (3,2,1)
SELECT t.* FROM
(SELECT `participant_id`, SUM( `vote` ) AS total_votes
FROM `votes`
GROUP BY `participant_id`
) t
JOIN (SELECT SUM( `vote` ) AS total_votes FROM `votes`
GROUP BY `participant_id`
ORDER BY `total_votes` DESC LIMIT 0 , 3 ) t1
USING(total_votes)
ORDER BY t.total_votes DESC
Fiddle Demo
What you want to do is following, as there is no total_votes column in your table:
SELECT `participant_id`, SUM( `vote` ) AS total_votes FROM `votes`
WHERE votes IN
(SELECT total_votes FROM
(SELECT DISTINCT (SUM( vote )) AS total_votes FROM `votes` GROUP BY `participant_id`
ORDER BY `total_votes` DESC LIMIT 0 , 3) AS temp )
GROUP BY `participant_id`
Check this simple query:
SELECT
participant_id, total_votes
FROM
(SELECT participant_id,SUM(vote) total_votes
FROM votes
GROUP BY participant_id) a
ORDER BY total_votes DESC
LIMIT 3;
To get all participants for top 3 voting you can use below query:
SELECT
a.participant_id, b.total_votes
FROM
(SELECT participant_id, SUM(vote) total_votes
FROM votes
GROUP BY participant_id) a
JOIN
(SELECT participant_id,SUM(vote) total_votes
FROM votes
GROUP BY participant_id
ORDER BY total_votes DESC LIMIT 3) b
ON a.total_votes=b.total_votes
ORDER BY total_votes DESC;

MySQL query to show records with current date on top and others as per descending order

I am using the following query in my database,
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b WHERE b.active=1
UNION
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b INNER JOIN tb_category c ON b.category_id=c.cat_id
WHERE c.cat_keyword LIKE 'a' ORDER BY sale_ends DESC
and getting the result as follows,
sales_id | category_id |sale_starts | sale_ends
----------|---------------------|------------|--------------
1 | 10 | 2012-03-31 | 2012-04-30
2 | 11 | 2012-03-22 | 2012-04-27
3 | 25 | 2012-03-31 | 2012-04-25
4 | 12 | 2012-04-05 | 2012-04-11
Now i need to get the result as follows, ie the row which has today's date/current date assale_ends must be shown in the top of the order (assuming today's date/current date is 2012-04-11), like shown below-
sales_id | category_id |sale_starts | sale_ends
----------|---------------------|------------|--------------
4 | 12 | 2012-04-05 | 2012-04-11 (today's date)
1 | 10 | 2012-03-31 | 2012-04-30
2 | 11 | 2012-03-22 | 2012-04-27
3 | 25 | 2012-03-31 | 2012-04-25
Need help in this, thanks in advance.
Try this ORDER BY clause with condition -
ORDER BY IF(sale_ends = DATE(NOW()), 0, 1), sale_ends DESC
You can wrap the whole thing in another SELECT and use ORDER BY
SELECT * FROM (
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b WHERE b.active=1
UNION
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b INNER JOIN tb_category c ON b.category_id=c.cat_id
WHERE c.cat_keyword LIKE 'a' ORDER BY sale_ends DESC
) AS all_sales
ORDER BY (sale_ends=CURDATE()) DESC, sale_ends DESC

Categories