I have a database where purchases are stored:
| user_id | product | price | datetime |
-----------------------------------------
| 1 | 1 | -0.75 | 2022-01-01 |
| 2 | 1 | -0.75 | 2022-01-01 |
| 3 | 2 | -0.65 | 2022-01-01 |
| 2 | 1 | -0.75 | 2022-01-01 |
| 1 | 1 | -0.75 | 2022-01-02 |
| 1 | 3 | -1.50 | 2022-01-02 |
| 1 | 2 | -0.65 | 2022-01-02 |
| 2 | 1 | -0.75 | 2022-01-02 |
| 3 | 2 | -0.65 | 2022-01-02 |
| 3 | 3 | -1.50 | 2022-01-02 |
| 3 | 3 | -1.50 | 2022-01-02 |
N.B. Time is not important in this question.
What I want is a ranking per day for each user like this for user 1:
| datetime | product1 | product2 | product3 | total | ranking |
--------------------------------------------------------------------
| 2022-01-01 | 1 | 0 | 0 | 0.75 | 2 |
| 2022-01-02 | 1 | 1 | 1 | 2.90 | 2 |
Note that the ranking is calculated for each day.
The next query gives part of the table:
SELECT
DATE(`datetime`) AS datetime,
SUM(CASE WHEN product = 1 THEN 1 ELSE 0 END) AS product1,
SUM(CASE WHEN product = 2 THEN 1 ELSE 0 END) AS product2,
SUM(CASE WHEN product = 3 THEN 1 ELSE 0 END) AS product3,
SUM(CASE WHEN product = 1 THEN 0.75 ELSE 0 END)+SUM(CASE WHEN product = 2 THEN 0.65 ELSE 0 END)+SUM(CASE WHEN product = 3 THEN 1.5 ELSE 0 END) as total,
FROM `history`
WHERE user_id=1
GROUP BY DATE(`datetime`)
My question is very similar to this one: MySQL ranking, but I can't get it exactly how I want it. It is only possible to make a ranking for the day with all users. If I add the given rank feature it will look to the table and make 2022-01-02 as the first ranking (because 2.90 is higher than 0.75). How can I make the rank look to each day?
The question isn't completely clear. However, what I think you're asking is how to rank the purchases for all users, by day:
history_date
user_id
DailyTotal
totalRank
2022-01-01
2
1.50
1
2022-01-01
1
0.75
2
2022-01-01
3
0.65
3
2022-01-02
3
3.65
1
2022-01-02
1
2.90
2
2022-01-02
2
0.75
3
Then display the results for a single user. So the rankings for user_id = 1 would be:
history_date
user_id
DailyTotal
totalRank
2022-01-01
1
0.75
2
2022-01-02
1
2.90
2
One way is using window functions. Aggregate the total purchases per user, by day and rank the overall total with DENSE_RANK().
Note, instead of hard coding price values, use ABS() to obtain positive numbers.
WITH cte AS (
SELECT ttl.*
, DENSE_RANK() OVER(
PARTITION BY history_date
ORDER BY DailyTotal DESC
) AS TotalRank
FROM (
SELECT user_id
, product
, price
, CAST(`datetime` AS DATE) AS history_date
, SUM( ABS(price) ) OVER(
PARTITION BY user_id, CAST(`datetime` AS DATE)
) AS DailyTotal
FROM history
WHERE product IN (1,2,3)
) ttl
)
SELECT user_id
, history_date
, SUM(CASE WHEN product = 1 THEN 1 ELSE 0 END) AS product1
, SUM(CASE WHEN product = 2 THEN 1 ELSE 0 END) AS product2
, SUM(CASE WHEN product = 3 THEN 1 ELSE 0 END) AS product3
, DailyTotal
, TotalRank
FROM cte
WHERE user_id = 1
GROUP BY user_id
, history_date
, DailyTotal
, TotalRank
;
Results:
user_id
history_date
product1
product2
product3
DailyTotal
TotalRank
1
2022-01-01
1
0
0
0.75
2
1
2022-01-02
1
1
1
2.90
2
db<>fiddle here
Related
I have 2 tables
and i want the result as this using join query. I don't have any Idea
Join Query By
TBL_SUCCESS_ORDER
------------------------
id | date | amount
-------------------------
1 | 2017-01-01 | 1000
2 | 2017-01-06 | 300
3 | 2017-01-29 | 50
4 | 2017-02-02 | 100
5 | 2017-02-16 | 400
6 | 2017-03-01 | 500
7 | 2017-04-03 | 1200
TBL_FAIL_ORDER
------------------------
id | date | amount
-------------------------
1 | 2017-01-03 | 400
2 | 2017-01-07 | 300
3 | 2017-01-24 | 50
4 | 2017-02-02 | 100
5 | 2017-04-07 | 200
RESULT
------------------------------------------------------------------
year | month | sum_of_succes_amount | sum_of_fail_amount | total
------------------------------------------------------------------
2017 | January | 1350 | 750 | 2100
2017 | Febuary | 500 | 100 | 600
2017 | March | 500 | 0 | 500
2017 | April | 1200 | 200 | 1400
I been stack for a whole week i did not get it . When i connect api json
TBL_PENDING_ORDER
------------------------
id | date | amount
-------------------------
1 | 2017-04-03 | 600
2 | 2017-05-07 | 600
RESULT
-----------------------------------------------------------------------------------------
year | month | sum_of_succes_amount | sum_of_fail_amount | sum_of_pending_amount |total
-----------------------------------------------------------------------------------------
2017 | January | 1350 | 750 | 0 | 2100
2017 | Febuary | 500 | 100 | 0 | 600
2017 | March | 500 | 0 | 0 | 500
2017 | April | 1200 | 200 | 600 | 2000
2017 | May | 0 | 0 | 600 | 600
What if I add The third table ? TBL_PENDING_ORDER
You can use the following solution using UNION ALL AND GROUP BY:
SELECT
YEAR(x.date),
MONTH(x.date),
SUM(CASE WHEN x.type = 'S' THEN amount ELSE 0 END) AS sum_of_succes_amount,
SUM(CASE WHEN x.type = 'F' THEN amount ELSE 0 END) AS sum_of_fail_amount,
SUM(amount) AS total
FROM (
SELECT id, date, amount, 'S' AS type FROM TBL_SUCCESS_ORDER
UNION ALL
SELECT id, date, amount, 'F' AS type FROM TBL_FAIL_ORDER
)x GROUP BY YEAR(x.date), MONTH(x.date)
You want to add the third table TBL_PENDING_ORDER?
SELECT
YEAR(x.date),
MONTH(x.date),
SUM(CASE WHEN x.type = 'S' THEN amount ELSE 0 END) AS sum_of_succes_amount,
SUM(CASE WHEN x.type = 'F' THEN amount ELSE 0 END) AS sum_of_fail_amount,
SUM(CASE WHEN x.type = 'P' THEN amount ELSE 0 END) AS sum_of_pending_amount,
SUM(amount) AS total
FROM (
SELECT id, date, amount, 'S' AS type FROM TBL_SUCCESS_ORDER
UNION ALL
SELECT id, date, amount, 'F' AS type FROM TBL_FAIL_ORDER
UNION ALL
SELECT id, date, amount, 'P' AS type FROM TBL_PENDING_ORDER
)x GROUP BY YEAR(x.date), MONTH(x.date)
I have a table order_details like this
id | SKU | quantity_purchased | discount_price
---------------------------------------------------
1 | abc | 1 | 10.0
2 | abc | 90 | 00
2 | abc | 9 | 00
3 | xyz | 1 | 50.0
3 | xyz | 2 | 50.0
4 | xyz | 100 | 00
4 | xyz | 100 | 00
-----------------------------------------------
My query is
select
(select sum(quantity_purchased) from order_details where discount_price > 0.00) as qty_discount,
(select sum(quantity_purchased) from order_details where discount_price = 0.00)as qty_original,
sku
from order_details
GROUP BY sku
my required result is
SKU | quantity_original | quantity_discount
---------------------------------------------------
abc | 1 | 99
xyz | 3 | 200
-----------------------------------------------
that is, I need two columns for same sku after calculation,
I am unable to establish the logic, I have tried using GROUP BY in nested query, but it doesn't work...
any help is highly appreciated..
thanks
UPDATE:
trying to do via this but still a failure,
select
(select sum(quantity_purchased) from order_details where discount_price > 0.00 ) as qty_discount,
(select sum(quantity_purchased) from order_details where discount_price = 0.00 )as qty_original,
sku
from order_details
where sku = (select distinct sku from order_details)
GROUP BY sku
You can use conditional aggregation for this:
select sku,
sum(case when discount_price != 0 then quantity_purchased
else 0
end) quantity_original,
sum(case when discount_price = 0 then quantity_purchased
else 0
end) quantity_discount
from order_details
group by sku
SQL Fiddle Demo
Results:
| SKU | quantity_original | quantity_discount |
|-----|-------------------|-------------------|
| abc | 1 | 99 |
| xyz | 3 | 200 |
I have data where each row represents one sentence in full review. Each row has a score (-1 to 1).
From that view I currently make 3 views where each has different group by, either by day, month or week and which aggregates average score for a review and
counts how many of them are positive and how many negative.
For example daily query from view:
SELECT
`review_score_view`.`review_date` AS `review_date`,
COUNT(`review_score_view`.`review_id`) AS `review_count`,
(AVG(`review_score_view`.`score`) * 100) AS `average_score`,
SUM((CASE
WHEN (`review_score_view`.`score` >= 0) THEN 1
ELSE 0
END)) AS `positive_count`,
SUM((CASE
WHEN (`review_score_view`.`score` < 0) THEN 1
ELSE 0
END)) AS `negative_count`
FROM
`review_score_view`
GROUP BY `review_score_view`.`review_date`
And I get result like this:
| id | review_date | review_count | average_score | positive_count | negative_count |
|-----|--------------|--------------|-----------------|----------------|----------------|
| 521 | 2015-01-01 | 4 | -25.0000 | 2 | 2 |
| 519 | 2015-01-07 | 1 | -100.0000 | 0 | 1 |
| 518 | 2015-01-25 | 1 | 100.0000 | 1 | 0 |
| 516 | 2015-03-09 | 7 | 57.1429 | 6 | 1 |
| 515 | 2015-04-26 | 2 | -50.0000 | 1 | 1 |
| 224 | 2015-06-01 | 68 | -23.5294 | 40 | 28 |
| 222 | 2015-06-02 | 26 | -100.0000 | 1 | 25 |
| 221 | 2015-06-03 | 41 | -36.5854 | 19 | 22 |
| 220 | 2015-06-04 | 6 | -50.0000 | 2 | 4 |
Question: How I can make another query from these view results based on average score. For each result (score categories), based on group by, either monthly, weekly or daily, I'd like to get a sum of these 5 results. Seems like an easy thing but I can't get my head around it.
SUM((CASE
WHEN (average_score >= 75) THEN 1
ELSE 0
END)) AS very_positive,
SUM((CASE
WHEN (average_score between 4 and 74) THEN 1
ELSE 0
END)) AS positive,
SUM((CASE
WHEN (average_score between -5 and 5) THEN 1
ELSE 0
END)) AS neutral,
SUM((CASE
WHEN (average_score between -4 and -74) THEN 1
ELSE 0
END)) AS negative,
SUM((CASE
WHEN (average_score <= -75) THEN 1
ELSE 0
END)) AS very_negative
Finally I would just plot the data. Quick example made in Excel:
Thanks in advance.
Hmmm. It looks like you want the results in rows, not columns. This suggests group by:
SELECT (CASE WHEN average_score >= 75 THEN 'VeryPositive'
WHEN average_score >= 4 THEN 'Positive'
WHEN average_score >= -5 THEN 'Neutral'
WHEN average_score >= -74 THEN 'Negative'
ELSE 'VeryNegative'
END) as ScoreGroup,
COUNT(*) as cnt
FROM dailyview v
GROUP BY ScoreGroup
ORDER BY ScoreGroup;
Note: The case returns the first expression that matches, so the between is unnecessary.
My scenario is... I have 2 type of judges who will give different set of points to members (eg. Judge Type A(55%) and Judge Type B(45%)) Both set of points will sum separately and averaged and then will sum together (which is 100% in total of 2 judges' points). I want to union both results into expected output below.
Table Member
-----------------------------
ID | Name
1 | John
2 | Doe
-----------------------------
Table Judge
-----------------------------
ID | Type | Name
1 | 1 | Judge A
2 | 1 | Judge B
3 | 2 | Judge C
4 | 1 | Judge D
-----------------------------
Table Point
-----------------------------
ID | FK | Judge | Type | Point
1 | 1 | 1 | 1 | 10
2 | 1 | 1 | 2 | 15
3 | 1 | 1 | 3 | 15
4 | 2 | 2 | 1 | 8
5 | 2 | 2 | 2 | 6
6 | 2 | 2 | 3 | 5
7 | 2 | 3 | 4 | 3
8 | 2 | 3 | 5 | 2
9 | 2 | 3 | 6 | 1
10 | 2 | 4 | 1 | 3
11 | 2 | 4 | 2 | 6
12 | 2 | 4 | 3 | 12
-----------------------------
Output Total Points
-----------------------------
ID | Name | Type1 | Type2 | Type3 | Total1 | CountJudge1 | Type4 | Type5 | Type6 | Total2 | CountJudge2
1 | John | 10 | 15 | 15 | 40 | 1 | 0 | 0 | 0 | 0 | 0
2 | Doe | 11 | 12 | 17 | 40 | 2 | 3 | 2 | 1 | 6 | 1
-----------------------------
Expected Output
-----------------------------
ID | Name | Type1 | Type2 | Type3 | Total1 | CountJudge1 | Type4 | Type5 | Type6 | Total2 | CountJudge2 | TotalPoint
1 | John | 10 | 15 | 15 | 40 | 1 | 0 | 0 | 0 | 0 | 0 | 40
2 | Doe | 5.5 | 6 | 8.5 | 20 | 2 | 3 | 2 | 1 | 6 | 1 | 26
-----------------------------
The sql (Output Total Points) that I could do at this moment which is still wrong is below and I can't figure out how to average all types of point and total points.
SELECT m.Name,
COUNT( CASE WHEN j.Type=1 THEN j.ID ELSE 0 END ) AS Judge1,
SUM( CASE WHEN p.Type=1 THEN p.Point ELSE 0 END ) AS Type1,
SUM( CASE WHEN p.Type=2 THEN p.Point ELSE 0 END ) AS Type2,
SUM( CASE WHEN p.Type=3 THEN p.Point ELSE 0 END ) AS Type3,
SUM( p.Score ) AS Total1,
COUNT( CASE WHEN j.Type=2 THEN j.ID ELSE 0 END ) AS Judge2,
SUM( CASE WHEN p.Type=4 THEN p.Point ELSE 0 END ) AS Type4,
SUM( CASE WHEN p.Type=5 THEN p.Point ELSE 0 END ) AS Type5,
SUM( CASE WHEN p.Type=6 THEN p.Point ELSE 0 END ) AS Type6,
SUM( p.Score ) AS Total2
FROM table_point AS p
LEFT JOIN table_member AS m ON ( m.ID = p.FK)
LEFT JOIN table_judge AS j ON ( j.ID = p.Judge )
GROUP BY m.ID
* UPDATE 1 *
I figured out the statement for expected result. However, as data grows bigger, my statement get slower. (250 members, 13 judges, 9750 scores (3 scores per judge per student) takes bout +-6 seconds). When I doubled members and scores, the execution time also doubled. Any idea to optimize this query?
SELECT MemberID, MemberName,
Judge1, Score1, Score2, Score3,
Judge2, Score4, Score5, Score6,
(((Score1 + Score2 + Score3) / (Judge1 / 3)) + ((Score4 + Score5 + Score6) / (Judge2 / 3))) AS TotalScore
FROM
(
SELECT m.ID AS MemberID, m.Name AS MemberName,
COUNT(j1.ID) AS Judge1,
SUM(CASE WHEN p.TypeID=1 THEN p.Point ELSE 0 END) AS Score1,
SUM(CASE WHEN p.TypeID=2 THEN p.Point ELSE 0 END) AS Score2,
SUM(CASE WHEN p.TypeID=3 THEN p.Point ELSE 0 END) AS Score3,
COUNT(j2.ID) AS Judge2,
SUM(CASE WHEN p.TypeID=4 THEN p.Point ELSE 0 END) AS Score4,
SUM(CASE WHEN p.TypeID=5 THEN p.Point ELSE 0 END) AS Score5,
SUM(CASE WHEN p.TypeID=6 THEN p.Point ELSE 0 END) AS Score6
FROM table_point AS p
LEFT JOIN table_member AS m ON ( m.ID = p.FK)
LEFT JOIN table_judge AS j1 ON ( j1.ID = p.Judge AND j1.Type=1 )
LEFT JOIN table_judge AS j2 ON ( j2.ID = p.Judge AND j2.Type=2 )
GROUP BY m.ID
) as tbl1
ORDER BY TotalScore DESC
Greets! I have 12 tables, one for each month of the year:
January
+----+-----+
| id | sale|
+----+-----+
| 1 | 250 |
| 3 | 500 |
| 5 | 200 |
| 7 | 100 |
+----+-----+
February
+----+-----+
| id | sale|
+----+-----+
| 1 | 350 |
| 2 | 400 |
| 3 | 500 |
| 4 | 800 |
+----+-----+
etc.
I need to do a query where the result is something like this:
Annual Sales
+----+-----------+-----------+
| id | Sales_Jan | Sales_Feb |
+----+-----------+-----------+
| 1 | 250 | 350 |
| 2 | 0 | 400 |
| 3 | 500 | 500 |
| 4 | 0 | 800 |
| 5 | 200 | 0 |
| 7 | 100 | 0 |
+----+-----------+-----------+
Where the matching ids from both tables do not duplicate and the missing ids from other months are shown by putting a 0 or any other symbol indicating that there was not any sales that month from that id.
Thank you very much!
You can approach this using union all and aggregation:
select id,
sum(case when month = 'Jan' then sale else 0 end) as Jan_Sale,
sum(case when month = 'Feb' then sale else 0 end) as Feb_Sale,
. . .
sum(case when month = 'Dec' then sale else 0 end) as Dec_Sale
from ((select 'Jan' as month, id, sale from January) union all
(select 'Feb' as month, id, sale from February) union all
. . .
(select 'Dec' as month, id, sale from February)
) t
group by id;