MySQL query - get sum of counts depending on column - mysql

I have a mysql table with actions and question_ids. Each action comes with a score like this:
ACTION | SCORE
downvote_question | -1
upvote_question | +1
in_cardbox | +2
I want to query for the question with the highest score but I can't figure it out.
http://sqlfiddle.com/#!2/84e26/15
So far my query is:
SELECT count(*), l1.question_id, l1.action
FROM `log` l1
GROUP BY l1.question_id, l1.action
which gives me every question_id with all its accumulated actions.
What I want is this:
QUESTION_ID | SCORE
2 | 5
1 | 4
3 | 1
4 | 1
5 | 1
I can't figure it out - I probably need subqueries, JOINS or UNIONS...

Maybe you can try this one.
SELECT a.question_id, sum(b.score) totalScore
FROM `log` a INNER JOIN scoreValue b
on a.`action` = b.actionname
group by a.question_id
ORDER BY totalScore DESC
SQLFiddle Demo

You should replace count(*) with sum(l1.score) because sum will add all values based on group by statement
SELECT sum(l1.score), l1.question_id, l1.action
FROM `log` l1
GROUP BY l1.question_id, l1.action
With constant scores works on SQL Fiddle (with grouping by question):
SELECT
sum(
CASE WHEN l1.action = 'downvote_question' THEN -1
WHEN l1.action = 'upvote_question' THEN 1
ELSE 2 END
) score,
l1.question_id
FROM `log` l1
GROUP BY l1.question_id

SELECT sum(SCORE), l1.question_id, l1.action
FROM `log` l1
GROUP BY l1.question_id, l1.action
is it what you want to?
upd: in your code on fidel, there is no such column as score, but i think it wont be a problem to create a tabel with action | score and join it to sum(score)

Related

Group by Member but Order by Count Product

I want to display promos from all members in the order of the highest number of clicks in the last 1 week, terms that 1 member only displays 1 promo
like this:
id promo
member/sales
order by count
9
B
10
5
A
9
6
M
8
The following is the data table
Tabel Promo (product_promo)>> | ppo_id | ppo_sales | ppo_content |
Tabel click recording (ipslsprod) >> | idip | dipp (id promo) | mxd (datetime visit click)
Tabel sales (sales) >> | id | name |
And I've written down the code
SELECT pp.*,
s.*,
Count(ip.dipp) AS VIEWS
FROM product_promo pp
left join (SELECT *
FROM ipslsprod
WHERE mxd >= Date_sub(Now(), interval 7 day)) ip
ON ip.dipp = pp.ppo_id
left join sales s
ON pp.ppo_sales = s.id
GROUP BY pp.ppo_id
ORDER BY VIEWS DESC
But showing more than 1 member
id promo
member/sales
order by count
9
B
10
5
A
9
4
B
7
I've tried changing
GROUP BY pp.ppo_sales
The data is messy.
Please help and instructions,
I want to display each sales only 1 product_promo in the order of the highest number of ip.dipps.
You can use aggregation and window functions. I'm not sure exactly what the query is, but I think:
SELECT v.*
FROM (SELECT s.id, pp.id_product_promo, COUNT(*) AS views ,
ROW_NUMBER() OVER (PARTITION BY s.id ORDER BY COUNT(*) DESC) as seqnum
FROM sales s JOIN
product_promo pp
ON pp.ppo_sales = s.id JOIN
ipslsprod ip
ON ip.dipp = pp.ppo_id
WHERE ip.mxd >= DATE_SUB(NOW(),INTERVAL 7 day)) ip
GROUP BY s.id, pp.id_product_promo
) v
WHERE seqnum = 1;
Maybe this will enlighten a bit more:
SELECT your_fields, MAX(count_click) FROM [table] GROUP BY count_click ORDER BY count_click
From there you can add all the date related stuff to fine-tune the query.
Perhaps it is a good idea to read up on the MySQL INTERVAL for that.

Finding users with at least one of every item

For example, I have the following table called, Information
user_id | item
-------------------------
45 | camera
36 | smartphone
23 | camera
1 | glucose monitor
3 | smartwatch
2 | smartphone
7 | smartphone
2 | camera
2 | glucose monitor
2 | smartwatch
How can I check which user_id has at least one of every item?
The following items will not be static and may be different everytime. However in this example there are 4 unique items: camera, smartphone, smartwatch, glucose monitor
Expected Result:
Because user_id : 2 has at least one of every item, the result will be:
user_id
2
Here is what I attempted at so far, however if the list of items changes from 4 unique items to 3 unique items, I don't think it works anymore.
SELECT *
FROM Information
GROUP BY Information.user_id
having count(DISTINCT item) >= 4
One approach would be to aggregate by user_id, and then assert that the distinct item_id count matches the total distinct item_id count from the entire table.
SELECT
user_id
FROM Information
GROUP BY
user_id
HAVING
COUNT(DISTINCT item_id) = (SELECT COUNT(DISTINCT item_id) FROM Information);
You can try to use self-join by count and total count
SELECT t1.user_id
FROM (
SELECT user_id,COUNT(DISTINCT item) cnt
FROM T
GROUP BY user_id
) t1 JOIN (SELECT COUNT(DISTINCT item) cnt FROM T) t2
WHERE t1.cnt = t2.cnt
or exists
Query 1:
SELECT t1.user_id
FROM (
SELECT user_id,COUNT(DISTINCT item) cnt
FROM T
GROUP BY user_id
) t1
WHERE exists(
SELECT 1
FROM T tt
HAVING COUNT(DISTINCT tt.item) = t1.cnt
)
Results:
| user_id |
|---------|
| 2 |
One more way of solving this problem is by using CTE and dense_rank function.
This also gives better performance on MySQL. The Dense_Rank function ranks every item among users. I count the number of distinct items and say pick the users who have the maximum number of distinct items.
With Main as (
Select user_id
,item
,Dense_Rank () over (
Partition by user_id
Order by item
) as Dense_item
From information
)
Select
user_id
From Main
Where
Dense_item = (
Select
Count(Distinct item)
from
information);

selecting multiple max values

i have a table like this on a mysql database:
id | item
-----------
1 | 2
2 | 2
3 | 4
4 | 5
5 | 8
6 | 8
7 | 8
i want the result to be 3 record with the highest Item value
select max(item) returns only 1 value
how can i select multiple max values?
thank you
You can use a derived table to get the maximum value and join it back to the original table to see all rows corresponding to it.
select t.id, t.item
from tablename t
join (select max(item) as mxitem from tablename) x
on x.mxitem = t.item
Edit:
select t.co_travelers_id, t.booking_id, t.accounts_id
from a_co_travelers t
join (select accounts_id, max(booking_id) as mxitem
from a_co_travelers
group by accounts_id) x
on x.mxitem = t.booking_id and t.accounts_id = x.accounts_id
If you use an 'aggregate function' without GROUP BY only one row will be returned.
You may use GROUP BY , with aggregate functions.
Here is SQLFiddle Demo
SELECT id,max(item) AS item
FROM table_name
GROUP BY id
ORDER BY item DESC
LIMIT 3
Hope this helps.
There is the graphical explanation.
There is script mysql (low abstraction level, no inner join or sth)
select * from ocena, uczen where ocena.ocena = (SELECT MAX(ocena.ocena) FROM ocena WHERE ocena.przedmiot_id="4" and ocena.uczen_id="1") and ocena.uczen_id=uczen.id and ocena.przedmiot_id="4" and uczen_id="1"

ORDER BY before GROUP BY for leaderboard

I have a table with all players results:
id |result| user_id
------------------------
1 | 130 | 5C382072
2 | 145 | 5C382072
3 | 130 | 8QHDTz7w
4 | 166 | 6155B6D0
5 | 100 | DFSA3444
Smaller result is better. I need to make query for leaderboard.
Each player must appear once in leaderboard with his best result. If 2 players have equal results, the one with smaller id should appear first.
So I'm expecting this output:
id |result| user_id
------------------------
5 | 100 | DFSA3444
1 | 130 | 5C382072
3 | 130 | 8QHDTz7w
4 | 166 | 6155B6D0
I can't get desired result, cause grouping by user_id goes before ordering it by result, id.
My code:
SELECT id, MIN(result), user_id
FROM results
GROUP BY user_id
ORDER BY result, id
It output something close to desired result, but id field is not connected to row with smallest user result, it can be any id from group with the same user_id. Because of that ordering by id not work at all.
EDIT:
What I didn't mention before is that I need to handle situations when user have identical results.
I came up with two solutions that I don't like. :)
1) A bit slow and ugly:
SELECT t1.*
FROM (SELECT * FROM results WHERE results_status=1) t1
LEFT JOIN (SELECT * FROM results WHERE results_status=1) t2
ON (t1.user_id = t2.user_id AND (t1.result > t2.result OR (t1.result = t2.result AND t1.id > t2.id)))
WHERE t2.id IS NULL
ORDER BY result, id
2) Ten times slower but more clear:
SELECT *
FROM results t1
WHERE id = (
SELECT id
FROM results
WHERE user_id = t1.user_id AND results_status=1
ORDER BY result, id
LIMIT 1
)
ORDER BY result, id
I'm stuck. :(
This should get you close. Avoid MySQL's lenient (errant) GROUP BY syntax, which lets you form a GROUP BY clause without naming unaggregated columns from the SELECT list. Use standard SQL's GROUP BY syntax instead.
select t.user_id, m.min_result, min(t.id) id
from results t
inner join (select user_id, min(result) min_result
from results
group by user_id) m
on t.user_id = m.user_id
and t.result = m.min_result
group by t.user_id, m.min_result
Edit: I think you need a subquery:
SELECT a.id, a.result, a.user_id FROM results a
WHERE a.user_id, a.result IN (SELECT b.user_id, MIN(b.result) FROM results b
GROUP BY b.user_id)
ORDER BY a.user_id
This will return an undefined id if the same user had the same score more than once, but will order the users correctly and will match id to the correct user_id.

Identifying groups in Group By

I am running a complicated group by statement and I get all my results in their respective groups. But I want to create a custom column with their "group id". Essentially all the items that are grouped together would share an ID.
This is what I get:
partID | Description
-------+---------+--
11000 | "Oven"
12000 | "Oven"
13000 | "Stove"
13020 | "Stove"
12012 | "Grill"
This is what I want:
partID | Description | GroupID
-------+-------------+----------
11000 | "Oven" | 1
12000 | "Oven" | 1
13000 | "Stove" | 2
13020 | "Stove" | 2
12012 | "Grill" | 3
"GroupID" does not exist as data in any of the tables, it would be a custom generated column (alias) that would be associated to that group's key,id,index, whatever it would be called.
How would I go about doing this?
I think this is the query that returns the five rows:
select partId, Description
from part p;
Here is one way (using standard SQL) to get the groups:
select partId, Description,
(select count(distinct Description)
from part p2
where p2.Description <= p.Description
) as GroupId
from part p;
This is using a correlated subquery. The subquery is finding all the description values less than the current one -- and counting the distinct values. Note that this gives a different set of values from the ones in the OP. These will be alphabetically assigned rather than assigned by first encounter in the data. If that is important, the OP should add that into the question. Based on the question, the particular ordering did not seem important.
Here's one way to get it:
SELECT p.partID,p.Description,b.groupID
FROM (
SELECT Description,#rn := #rn + 1 AS groupID
FROM (
SELECT distinct description
FROM part,(SELECT #rn:= 0) c
) a
) b
INNER JOIN part p ON p.description = b.description;
sqlfiddle demo
This gets assigns a diferent groupID to each description, and then joins the original table by that description.
Based on your comments in response to Gordon's answer, I think what you need is a derived table to generate your groupids, like so:
select
t1.description,
#cntr := #cntr + 1 as GroupID
FROM
(select distinct table1.description from table1) t1
cross join
(select #cntr:=0) t2
which will give you:
DESCRIPTION GROUPID
Oven 1
Stove 2
Grill 3
Then you can use that in your original query, joining on description:
select
t1.partid,
t1.description,
t2.GroupID
from
table1 t1
inner join
(
select
t1.description,
#cntr := #cntr + 1 as GroupID
FROM
(select distinct table1.description from table1) t1
cross join
(select #cntr:=0) t2
) t2
on t1.description = t2.description
SQL Fiddle
SELECT partID , Description, #s:=#s+1 GroupID
FROM part, (SELECT #s:= 0) AS s
GROUP BY Description