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

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;

Related

Get Rank by votes and number of same rank PHP MySQL

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

How to make query on another query result in MYSQL?

I have made a query like that to get result by joining 3 tables
QUERY 1
SELECT a.user_id, a.nick_id, count(b.invoice_id) AS INVOICES, sum(b.purchase_amount) AS PURCHASES, c.sponsor_id, c.user_first_name, c.user_last_name
FROM table1 a
INNER JOIN table2 b ON a.user_id = b.user_id
INNER JOIN table3 c ON a.user_id = c.user_id
WHERE b.purchase_date BETWEEN '2018-09-01 00:00:00' AND now() and a.user_id IS NOT NULL GROUP BY a.user_id ORDER BY PURCHASES DESC
Table1 (Example)
user_id | nick_id
1 | AGENT1
2 | AGENT2
3 | AGENT3
Table2 (Example)
user_id | invoice_id | purchase_amount | purchase_date
1 | IN001 | 500 | 2018-09-01 14:58:33
2 | IN002 | 1000 | 2018-09-18 22:46:12
Table3 (Example)
user_id | sponsor_id | user_first_name | user_last_name
2 | 1 | John | Doe
3 | 1 | Harry | Wilson
4 | 2 | Peter | Bennington
5 | 2 | Daisy | Cooper
Now on the result of [QUERY 1], I want to perform [QUERY 2]
QUERY 2
SELECT sponsor_id, user_id, user_first_name, user_last_name
FROM
(SELECT * FROM table3 ORDER BY sponsor_id, user_id) table3,
(SELECT #pv := '1') initialisation WHERE find_in_set(sponsor_id, #pv) > 0
AND #pv := concat(#pv, ',', user_id)
After that I will get my desired result. But I want to perform both queries at once in a single query.

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.

get id where price is max in mysql

My table is:
id code batch price qty
---|----- |----- |-----|---------
1 | 107 | 1 | 39 | 399
2 | 107 | 1 | 39 | 244
3 | 107 | 2 | 40 | 555
4 | 108 | 1 | 70 | 300
5 | 108 | 2 | 60 | 200
6 | 109 | 2 | 50 | 500
7 | 109 | 2 | 50 | 600
8 | 110 | 2 | 75 | 700
My desired result is (i want this result as output)
id code batch price
---|----- |----- |-----|
3 | 107 | 2 | 40 |
4 | 108 | 1 | 70 |
3 | 109 | 2 | 50 |
8 | 110 | 2 | 75 |
i write this query
SELECT `id`,`code`,`batch` max(`price`) FROM `table_name` where `qty` > 0 group by `code`
my output is
id code batch price
---|----- |----- |-----|
1 | 107 | 1 | 40 |
4 | 108 | 1 | 70 |
6 | 109 | 2 | 50 |
8 | 110 | 2 | 75 |
i need id and batch where the price is max
Another way to get highest record per group
select *
from demo a
where (
select count(*)
from demo b
where a.code = b.code
and case when a.price = b.price then a.id < b.id else a.price < b.price end
) = 0
I assume id is auto increment so in case there is a tie in max price from groups you can use a CASE to pick the latest id
Demo
You could use join on the max value grouped by code
select a.id, a.code, a.batch, b.max_price
from table_name a
inner join (
select code, max(price) as max_price
from table_name
group by code
) b on a.code = b.code and a.price = b.max_price
and if you have more that a row with same code, price you could use
select max(a.id), a.code, a.batch, b.max_price
from table_name a
inner join (
select code, max(price) as max_price
from table_name
group by code
) b on a.code = b.code and a.price = b.max_price
group by a.code, a.batch, b.max_price
select id,batch from table_name order by price desc limit 0,1
Sort by desc with price
Select the top row using limit
Order by the price and then limit the result to 1 :)
SELECT id, batch
FROM table_name
ORDER BY price DESC
LIMIT 1
Give a row number group by code and in the descending order of price columns. Then select the rows having row number 1.
Query
select t1.`id`, t1.`code`, t1.`batch`, t1.`price` from (
select `id`, `code`, `batch`, `price`, (
case `code` when #curA
then #curRow := #curRow + 1
else #curRow := 1 and #curA := `code` end
) as `rn`
from `MyTable` t,
(select #curRow := 0, #curA := '') r
order by `code`, `price` desc
)t1
where t1.`rn` = 1
order by `code`;
Find a demo here
Try this:
SELECT `id`,`code`,`batch`, `price`
FROM `table_name`
WHERE `qty` > 0
GROUP BY `code` HAVING `price` = max(`price`)
I didn't understand you need single result or multiple. but this works fine if you need only max id.
SELECT id
FROM table
WHERE id=(
SELECT max(price) FROM table
)
Note : if the value of max(id) is not unique, multiple rows are returned.
try this
SELECT MAX(price) AS price, id, batch
FROM table_name

Categories