MYSQL GROUP BY and SUM with clause - mysql

Hello there are two tables
Interval
id
is_full
1
1
2
0
3
0
entry_penalty
interval_id
entry_id
amount
2
14
55
3
14
7
3
14
1
1
15
4
1
15
8
2
15
11
So i am trying to display Sum of all entry_penalties per interval, twist is even if there is no relation between entry_penalty and interval table i should display full course interval sum per entry_id (related to is_full field).
For example total results should be in this case
interval_id
entry_id
amount
1
14
63
2
14
55
3
14
8
1
15
23
2
15
11
I have tried with sub query but it ignores to do calculation when there is no relation between entry_penalties and interval tables regarding is_full column.
My code so far.
SELECT
ep.interval_id,
IF (
i.is_full,
(
SELECT SUM(ep2.amount) * 1000 FROM entry_penalty as ep2
WHERE ep2.entry_id = ep.entry_id
),
SUM(ep.amount) * 1000
) as penalty_time,
ep.entry_id
FROM entry_penalty ep
INNER JOIN \`interval\` i ON i.id = ep.interval_id
WHERE ep.entry_id IN (:entryIds)
GROUP BY interval_id, entry_id`

I would propose to deal with the two cases (full, not full) separately, and then use union all to combine the two results:
SELECT i.id, ep.entry_id, SUM(ep.amount)
FROM `interval` i,
entry_penalty ep
WHERE i.is_full
GROUP BY i.id, ep.entry_id
UNION ALL
SELECT i.id, ep.entry_id, SUM(ep.amount)
FROM entry_penalty ep
INNER JOIN `interval` i
ON ep.interval_id = i.id
AND NOT i.is_full
GROUP BY i.id, ep.entry_id
ORDER BY 2, 1
See it run on dbfiddle.uk, where it outputs:
id
entry_id
SUM(ep.amount)
1
14
63
2
14
55
3
14
8
1
15
23
2
15
11

Related

Query within a query to obtain certain value with multiple joins in MySQL Select

I have 3 tables that I have joined in the MySQL query below. All works well EXCEPT I would like the timeadj value with a 1 in column countingtime
to show from table 'data', not the first timeadj value the query finds.
I know this needs to be a query within a query but I am going around in circles and getting no where.
SELECT ttt_entries.tttid, ttt_teams.teamname, data.RacersInTeam,
ttt_entries.CoffeeClass, SEC_TO_TIME(data.timeadj),
COUNT(IF(data.division=5,1,NULL)) 'A+',
COUNT(IF(data.division=10,1,NULL)) A,
COUNT(IF(data.division=20,1,NULL)) B,
COUNT(IF(data.division=30,1,NULL)) C,
COUNT(IF(data.division=40,1,NULL)) D
FROM ttt_entries
INNER JOIN ttt_teams
ON ttt_entries.tttid = ttt_teams.tttid
INNER JOIN (SELECT * FROM data ORDER BY data.countingtime DESC) as data
ON ttt_entries.tttid = data.teamid
WHERE ttt_entries.eventDate = DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE()) >4, -5, 2) + DAYOFWEEK(CURDATE())) * -1 DAY) -- last Thursday
AND data.wtrlid = '22'
GROUP BY ttt_teams.tttid
ORDER BY data.timeadj ASC
For example.... In Team 1 (data.teamid=1) there are 8 time values in timeadj. In the adjacent column (countingtime) is a value either 1 or 0 but only ever 1x 1 per team.
Table ttt_entries
ID tttid CoffeeClass
1 23 Mocha
2 52 Espresso
3 6 Frappe
Table ttt_teams
tttid Name
6 Team A
23 Team 1
52 Team 2
Table 'data'
id wtrlid teamid timeadj countingtime division
1 22 23 3467.123 0 10
2 22 23 3467.125 0 20
3 22 23 3467.432 0 10
4 22 23 3469.000 1 10
5 22 23 3469.112 0 10
6 22 23 3468.987 0 5
My code brings back
tttid teamname RacersInTeam CoffeeClass Time A+ A B C D
23 Team 1 6 Mocha 3467.123 1 4 1 0 0
I need it to bring back the same data but a different time:
tttid teamname RacersInTeam CoffeeClass Time A+ A B C D
23 Team 1 6 Mocha 3469.000 1 4 1 0 0
You can try below way -
SELECT ttt_entries.tttid, ttt_teams.teamname, data.RacersInTeam,
ttt_entries.CoffeeClass, SEC_TO_TIME(max(case when countingtime=1 then data.timeadj end)),
COUNT(IF(data.division=5,1,NULL)) 'A+',
COUNT(IF(data.division=10,1,NULL)) A,
COUNT(IF(data.division=20,1,NULL)) B,
COUNT(IF(data.division=30,1,NULL)) C,
COUNT(IF(data.division=40,1,NULL)) D
FROM ttt_entries
INNER JOIN ttt_teams
ON ttt_entries.tttid = ttt_teams.tttid
INNER JOIN (SELECT * FROM data ORDER BY data.countingtime DESC) as data
ON ttt_entries.tttid = data.teamid
WHERE ttt_entries.eventDate = DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE()) >4, -5, 2) + DAYOFWEEK(CURDATE())) * -1 DAY) -- last Thursday
AND data.wtrlid = '22'
GROUP BY ttt_teams.tttid
ORDER BY data.timeadj ASC

Retrieve a column with the list of object_id's that occurs together more than once and a second column with the count of how many times it occurs

Note that object_id's 18,10 and 21 are associated to the cart_id 3 once. I wanna know whether the combination occurs again in another cart_id and how many times does that occurs over all the rows existent. I expect two columns as a resultset "combination" and "combination_occurrence_count"
It is quite complicated task to check all possible combinations as it is too many of them.
However, if you simplify your requirements a bit, you can get something useful.
Lets start with finding all combinations of two items. At the beginning you can try the following query:
SELECT
c1.cart_id AS cart1_id
, c1.object_id AS object1_id
, c2.object_id AS object2_id
, cx1.cart_id AS cartX_id
, cx1.object_id AS objectX1_id
, cx2.object_id AS objectX2_id
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
ORDER BY
c1.cart_id
, c1.object_id
, c2.object_id
, cx1.cart_id
, cx1.object_id
, cx2.object_id
There are two ideas behind the query:
Get all possible combinations of two object ids that are exist in
carts. Carts with only one item will be excluded. The only existing
combinations would be analyzed (instead of all possible combinations). [c1 & c2]
Find other carts that have the same object ids combinations [cx1 & cx2]
The results would be something like this:
cart1_id object1_id object2_id cartX_id objectX1_id objectX2_id
3 10 18 30 10 18
3 10 18 31 10 18
3 10 21 30 10 21
3 18 21 30 18 21
30 10 18 31 10 18
Then you can group these results to get "the most popular" pairs:
SELECT
cx1.object_id AS object1_id
, cx2.object_id AS object2_id
, 1 + COUNT(DISTINCT cx1.cart_id) AS cnt
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
GROUP BY
cx1.object_id
, cx2.object_id
ORDER BY
cnt DESC
LIMIT
20
Results:
object1_id object2_id cnt
10 18 3
10 21 2
18 21 2
So pair 10 + 18 is the most popular and are exist in 3 carts.
Pairs 10 + 21 and 18 + 21 are in 2 different carts.
You can continue and do something like this for 3-objects combinations.
P.S. I used the following data set (added a few rows to your data to get a bit more interesting results):
id cart_id object_id
10 2 24
9 3 10
3 3 18
19 3 21
12 4 24
1 7 30
5 9 24
2 11 10
20 14 12
14 14 18
8 14 27
13 15 11
7 16 9
18 16 13
15 20 11
6 21 6
4 23 5
17 23 6
16 25 16
11 29 11
23 30 1
21 30 10
22 30 18
24 30 21
25 31 10
26 31 18
P.P.S. I have not spent too much time on this so it is possible that I missed something in queries. However, I hope you understand the general idea.
The following returns the list of carts with all three objects:
select cart_id
from t
where object_id in (18, 10, 21)
group by cart_id
having count(distinct cart_id) = 3;
select group_concat(`app_item`.`object_id`) as `combination`
from `app_item`
group by `app_item`.`cart_id`
The query return a "combination" resultset as I was looking for:
Since I cannot group again using the "combination" and then make a count of occurrences for each combination and then get the "combination_occurrence_count" it contains, I am now doing this through a method in the application as following
and now I can display an array as key/pair like "combination" => "occurrence count" as following

group by month returns only April for two tables

Currently I am honestly at loss what I am doing wrong. It is a rather simple query I think.
Tables:
operations:
id processedon clientid
1 2018-01-01 9
2 2018-03-16 9
3 2018-04-21 9
4 2018-04-20 9
5 2018-05-09 9
items:
id operation_id quantity unitprice
1 1 10 2
2 1 5 3
3 2 20 4
4 3 10 2
5 4 8 4
6 4 10 4
7 5 2 2
The expected result of the operation/query is:
month total_value
1 35
3 80
4 92
5 4
That is quantity * unitprice based. For some reason, it only returns month=4
SELECT
month(`operations`.`processedon`) AS `month`,
SUM((`items`.`quantity` * `items`.`unitprice`)) AS `total_value`
FROM `items`
INNER JOIN `operations` ON (`items`.`operation_id` = `operations`.`id`)
GROUP BY 'month'
ORDER BY 'month'
According to the info provided the join should be
INNER JOIN operations ON items.operation_id = operations.id
Eg
SELECT
month(`operations`.`processedon`) AS `month`,
SUM((`items`.`quantity` * `items`.`unitprice`)) AS `total_value`
FROM `items`
INNER JOIN `operations` ON `items`.`operation_id` = `operations`.`id`
GROUP BY month(`operations`.`processedon`)
ORDER BY `month`
There is no efficiency gain by using a column alias in the group by clause, I prefer to avoid using them except perhaps in the order by clause.
The following query will give you the required answer
SELECT
month(`operations`.`processedon`) AS `month`,
SUM((`items`.`quantity` * `items`.`unitprice`)) AS `total_value`
FROM items
INNER JOIN operations ON (items.operation_id = operations.id)
GROUP BY month(operations.processedon)
ORDER BY month(operations.processedon)
You need to specify month correctly since it is not an existing column.
You'll get the following result
month total_value
1 35
3 80
4 92
5 4

mysql join two table rows in one table

I have two tables e_sku and e_availability, In e_sku table i have 45 rows with the default availability as 1, below is an example
id is_available name
1 1 UN001N
2 1 UN002N
3 1 UN003N
4 1 UN004N
5 1 UN005N
6 1 UN006N
7 1 UN007N
8 1 UN008N
9 1 UN009N
10 1 UN010N
11 1 UN011N
12 1 UN012N
13 1 UN013N
14 1 UN014N
15 1 UN015N
16 1 UN016N
17 1 UN017N
18 1 UN018N
19 1 UN019N
20 1 UN020N
21 1 UN021N
22 1 UN022N
23 1 UN023N
24 1 UN024N
25 1 UN025N
26 1 UN026N
27 1 UN027N
28 1 UN028N
29 1 UN029N
30 1 UN030N
31 1 UN031N
32 1 UN032N
33 1 UN033N
34 1 UN034N
35 1 UN035N
36 1 UN036N
37 1 UN037N
38 1 UN038N
39 1 UN039N
40 1 UN040N
41 1 UN041N
42 1 UN042N
43 1 UN043N
44 1 UN044N
45 1 UN045N
Second table is e_availability in this table i am only storing the unavailability with dates below is the example
id e_sku_id is_available working_date
1 5 0 10/20/2016
2 8 0 10/20/2016
3 10 0 10/20/2016
4 1 0 10/20/2016
5 15 0 10/20/2016
6 11 0 10/19/2016
7 1 0 10/19/2016
Because the data is capturing every date for unavailability so i am only gathering the unavailable product's data in e_availability table w.r.t. dates, Now i am looking to show the data for each day as complete skus in such a way that every day report will show 45 skus and for available sku it will show 1 from e_sku table's column is_available and for unavailable sku it will show the column of is_availability from e_availability table
I am using mysql database, I tried many join queries but not getting the report.
can any one guide about which join i require
I got the result by using this query
SELECT * FROM (SELECT id,NAME,1 AS is_available FROM e_sku
WHERE company_id = 2
AND id NOT IN (SELECT id FROM (SELECT e_sku.id,e_sku.name, edge_availability.is_available FROM edge_availability
JOIN edge_working ON edge_working.`id` = edge_availability.`working_id`
JOIN e_sku ON e_sku.id = edge_availability.`sku_id`
WHERE edge_working.`working_date` = '2016-10-19' AND edge_availability.`store_id` = 84) X)
UNION
SELECT e_sku.id,e_sku.name, edge_availability.is_available FROM edge_availability
JOIN edge_working ON edge_working.`id` = edge_availability.`working_id`
JOIN e_sku ON e_sku.id = edge_availability.`sku_id`
WHERE edge_working.`working_date` = '2016-10-19' AND edge_availability.`store_id` = 84) Y
ORDER BY id
You can use a LEFT JOIN to detect when a date isn't found in the e_availability table. The join will return NULL for all the columns in that table, then you can default to the value from e_sku.
SELECT d.date, s.id, IFNULL(a.is_available, s.is_available) AS is_available
FROM all_dates AS d
CROSS JOIN e_sku AS s
LEFT JOIN e_availability ON d.working_date = a.date AND s.id = a.e_sku_id
You need to create an additional table all_dates that contains all the dates that you want to report on. See What is the most straightforward way to pad empty dates in sql results (on either mysql or perl end)? for how you can create such a table dynamically.

mysql query issue while data recieving

Sql Query to retrieve data using table ##
I need query to get the count of participants in each level .
Note: participant who is in level 4 should not be in other levels ex: Level 3,2,1
Table :
ID Level date
38 1 06 -05
38 2 08 -05
38 3 12 -05
38 4 13 -05
39 1 13 -05
39 2 13 -05
40 1 12 -05
Needed Output:
Count Level
1 1
1 2
0 3
1 4
You can define an artadditional table (or create a subquery) which would return the 30 rows
e.g
(select now() as d
union
select date_sub(now(), interval 1 day) as d
union
select date_sub(now(), interval 2 day) as d
union
...
select date_sub(now(), interval 29 day) as d) all_dates_source
Then you can LEFT JOIN your query result to the all_dates_source
SELECT i,
Logindate2,
ifnull(Logindate2,0, Logins2) as Logins2
FROM (...) all_dates_source
LEFT JOIN (yourQueryHere) sourceQuery
on all_dates_source.d=sourceQuery.Logindate2
SELECT count(t2.ppt) as count,t1.Level as level
FROM courselevel t1
LEFT JOIN
(SELECT ppt,MAX(Level) as Level
FROM courselevel
GROUP BY ppt ) t2 on t1.ppt=t2.ppt and t1.Level=t2.Level
GROUP BY t1.Level