Mysql: sum case with multiple table - mysql

i have following table:
table1:
CREATE TABLE table1
(
id int auto_increment primary key,
person varchar(30),
color_code varchar(30),
item_id varchar(30),
date_start DATE,
date_complete DATE
);
INSERT INTO table1
(person, color_code, item_id, date_start, date_complete)
VALUES
('Jackson', 'RED', '1', '2013-07-11 11:23:39', '2013-08-1 11:23:39'),
('Danny', 'BLUE', '2', '2013-07-20 11:23:39', '2013-08-1 11:23:39'),
('Jimmy', 'GREEN', '5', '2013-05-15 11:23:39', '2013-08-1 11:23:39'),
('Jackson', 'RED', '3', '2013-02-16 11:23:39', '2013-08-1 11:23:39'),
('Jimmy', 'BLUE', '4', '2013-03-13 11:23:39', '2013-08-1 11:23:39'),
('William', 'RED', '5', '2013-04-29 11:23:39', '2013-08-1 11:23:39'),
('William', 'BLUE', '1', '2013-05-9 11:23:39', '2013-08-1 11:23:39'),
('Danny', 'GREEN', '5', '2013-01-6 11:23:39', '2013-08-1 11:23:39'),
('Jackson', 'RED', '4', '2013-07-11 11:23:39', '2013-08-1 11:23:39'),
('Jackson', 'RED', '5', '2013-08-7 11:23:39', '2013-09-1 11:23:39');
table2:
CREATE TABLE table2
(
id int auto_increment primary key,
item_code varchar(30),
item_name varchar(30)
);
INSERT INTO table2
(item_code, item_name)
VALUES
('1', 'APPLE'),
('2', 'BANANA'),
('3', 'PINEAPPLE'),
('4', 'WATERMELON'),
('5', 'GUAVA');
my sql query look like this:
SELECT
person AS 'Name',
COUNT(*) AS 'Total Item Purchased',
SUM(CASE WHEN (color_code='RED') THEN 1 ELSE 0 END) AS 'Total Red Color',
SUM(CASE WHEN (color_code='BLUE') THEN 1 ELSE 0 END) AS 'Total Blue Color',
SUM(CASE WHEN (color_code='GREEN') THEN 1 ELSE 0 END) AS 'Total Green Color',
SUM(CASE WHEN DATEDIFF(date_complete, date_start) BETWEEN 1 AND 30 THEN 1 ELSE 0 END) AS 'Bought Between 1-30 Days'
FROM table1
WHERE
person LIKE '%Jackson%' OR
person LIKE '%Danny%' OR
person LIKE '%Jimmy%' OR
person LIKE '%William%'
GROUP BY person;
Problem: How do i display the item_name from table2 to the select query with all the row group by the person? im thinking about subselect, after the 'Bought Between 1-30 Days' is it possible?
SQLFiddle: http://sqlfiddle.com/#!2/d59e0/4

You can join the tables and use GROUP_CONCAT():
SELECT
person AS 'Name',
COUNT(*) AS 'Total Item Purchased',
SUM(CASE WHEN (color_code='RED') THEN 1 ELSE 0 END) AS 'Total Red Color',
SUM(CASE WHEN (color_code='BLUE') THEN 1 ELSE 0 END) AS 'Total Blue Color',
SUM(CASE WHEN (color_code='GREEN') THEN 1 ELSE 0 END) AS 'Total Green Color',
SUM(CASE WHEN DATEDIFF(date_complete, date_start) BETWEEN 1 AND 30 THEN 1 ELSE 0 END) AS 'Bought Between 1-30 Days',
GROUP_CONCAT(item_name)
FROM table1 JOIN table2 ON table2.item_code = table1.item_id
WHERE
person LIKE '%Jackson%' OR
person LIKE '%Danny%' OR
person LIKE '%Jimmy%' OR
person LIKE '%William%'
GROUP BY person;
See it on sqlfiddle.
Note that it is sometimes better to simply join the tables and sort the resultset by person, performing such aggregation within the presentation layer of your application.

You can join the tables
SELECT
person AS 'Name',
COUNT(*) AS 'Total Item Purchased',
SUM(CASE WHEN (color_code='RED') THEN 1 ELSE 0 END) AS 'Total Red Color',
SUM(CASE WHEN (color_code='BLUE') THEN 1 ELSE 0 END) AS 'Total Blue Color',
SUM(CASE WHEN (color_code='GREEN') THEN 1 ELSE 0 END) AS 'Total Green Color',
SUM(CASE WHEN DATEDIFF(date_complete, date_start) BETWEEN 1 AND 30 THEN 1 ELSE 0 END) 'Bought Between 1-30 Days',
item_name as 'item'
FROM table1,table2
WHERE
table1.item_id = table2.item_code and (
person LIKE '%Jackson%' OR
person LIKE '%Danny%' OR
person LIKE '%Jimmy%' OR
person LIKE '%William%')
GROUP BY person;
Check the js http://sqlfiddle.com/#!2/d59e0/13

Related

MySQL query to create a report

Hello Can any one help me with this query
INSERT INTO userrole (Id, Name, Description, IsEnabled, Created, CreatedBy, Updated, UpdatedBy) VALUES
(1, 'Role_1', '', 1, '2020-04-14 18:30:00', 'Admin', NULL, NULL),
(2, 'Role_2', 'Description', 1, '2020-04-15 18:30:00', 'ADMIN', '2020-04-16 18:30:00', 'John Smith'),
(3, 'Role_3', 'Description', 0, '2020-04-15 18:30:00', 'John SMITH', '2020-04-16 18:30:00', 'Ben SMITH'),
(4, 'Role_4', 'Description', 1, '2020-04-18 18:30:00', 'bEn SmiTh', '2020-04-20 18:30:00', 'BEN SMITH');
SELECT
UPPER(CreatedBy) AS UserName,
COUNT(UPPER(CreatedBy)) AS NoOfCreatedRoles,
SUM(CASE
WHEN IsEnabled = 1 THEN 1
ELSE - 1
END) AS NoOfCreatedAndEnabledRoles,
CASE
WHEN UpdatedBy IS NOT NULL THEN COUNT(UPPER(UpdatedBy)) ELSE -1
END AS NoOfUpdatedRoles
FROM UserRole
GROUP BY CreatedBy
ORDER BY CreatedBy desc
Give a try with this:
SELECT Result.UserName, Result.NoOfCreatedRoles, Result.NoOfCreatedAndEnabledRoles, Result.NoOfUpdatedRoles
FROM (
Select UPPER(TRIM(CreatedBy)) AS 'UserName',
COUNT(UPPER(CreatedBy)) AS NoOfCreatedRoles,
SUM(CASE WHEN IsEnabled = 1 THEN 1 ELSE - 1 END) AS NoOfCreatedAndEnabledRoles,
(SELECT CASE when COUNT(*) = 0 THEN -1 ELSE Count(*) END
FROM UserRole as URQ
WHERE URQ.UpdatedBy = UR.CreatedBy) AS NoOfUpdatedRoles
FROM UserRole UR
GROUP BY CreatedBy
ORDER BY UserName
) as Result
ORDER BY NoOfCreatedRoles

SQL Get most frequent value from a column based on a condition

This query
SELECT
PlayerID, HeroTypeID, HeroTypeIDCount, Wins / (Losses + Wins) AS WinRate, Wins, Losses
FROM (
SELECT E.PlayerID AS PlayerID,
FK_HeroTypeID AS HeroTypeID,
COUNT(FK_HeroTypeID) AS HeroTypeIDCount,
SUM(CASE WHEN D.Result = 'LOSS' THEN 1 ELSE 0 END) AS Losses,
SUM(CASE WHEN D.Result = 'WIN' THEN 1 ELSE 0 END) AS Wins
FROM GamePlayerDetail D
JOIN Player E
ON D.FK_PlayerID = E.PlayerID
JOIN Game I
ON D.FK_GameID = I.GameID
WHERE PlayedDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 7 DAY) AND CURDATE()
GROUP BY E.PlayerID, FK_HeroTypeID
) AS T
ORDER BY PlayerID
produces the following result:
# PlayerID, HeroTypeID, HeroTypeIDCount, WinRate, Wins, Losses
'1', '11', '1', '1.0000', '1', '0'
'1', '13', '3', '0.3333', '1', '2'
'1', '24', '5', '0.8000', '4', '1'
'1', '27', '1', '1.0000', '1', '0'
'2', '28', '1', '0.0000', '0', '1'
'2', '6', '1', '0.0000', '0', '1'
'2', '30', '1', '0.0000', '0', '1'
'2', '7', '1', '1.0000', '1', '0'
What I'd like to do is get the most frequent FK_HeroTypeID (which is also highest value of HeroTypeIDCount) per PlayerID, but in case of ties, the highest winrate should take precedence. Here's an example of what I'd like to get:
PlayerID, HeroTypeID, HeroTypeIDCount, WinRate, Wins, Losses
1, 24, 5, 0.8000, 4, 1
2, 7, 1, 1.0000, 1, 0
How should you write a query like this?
Edit:
Ok, here's a simple Create/Insert table for the produced result.
http://sqlfiddle.com/#!9/d644a
SELECT playerid
, herotypeid
, herotypeidcount
, winrate
, wins
, losses
FROM
( SELECT *
, CASE WHEN #prev=playerid THEN #i:=#i+1 ELSE #i:=1 END rank
, #prev:=playerid prev
FROM table1
, (SELECT #prev:=null,#i:=0) vars
ORDER
BY herotypeidcount DESC
, winrate DESC
) x
WHERE rank = 1;
Here's a 'hack' solution. It works, but really shouldn't be relied upon...
SELECT *
FROM
( SELECT *
FROM table1
ORDER
BY herotypeidcount DESC
, winrate DESC
) x
GROUP
BY playerid

MySQL pivoting not working as expected

Schema:
DROP TABLE IF EXISTS `questions_tags`;
CREATE TABLE `questions_tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag_id` int(11) NOT NULL,
`question_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `questions_tags` VALUES ('1', '1', '1');
INSERT INTO `questions_tags` VALUES ('2', '2', '1');
INSERT INTO `questions_tags` VALUES ('3', '3', '1');
INSERT INTO `questions_tags` VALUES ('4', '4', '1');
INSERT INTO `questions_tags` VALUES ('5', '5', '1');
INSERT INTO `questions_tags` VALUES ('6', '2', '2');
Data:
id tag_id question_id
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
6 2 2
What I've tried:
SELECT
question_id,
CASE WHEN tag_id = 1 THEN 'TAG1' END AS FirstTag,
CASE WHEN tag_id = 2 THEN 'TAG2' END AS SecondTag,
CASE WHEN tag_id = 3 THEN 'TAG3' END AS ThirdTag,
CASE WHEN tag_id = 4 THEN 'TAG4' END AS FourthTag,
CASE WHEN tag_id = 5 THEN 'TAG5' END AS FifthTag
FROM questions_tags
GROUP BY question_id;
Current Output:
Expected Output:
Is there something that I misjudged about Pivoting? Any help is appreciated.
Use aggregation on the case expressions.
SELECT
question_id,
max(CASE WHEN tag_id = 1 THEN 'TAG1' END) AS FirstTag,
max(CASE WHEN tag_id = 2 THEN 'TAG2' END) AS SecondTag,
max(CASE WHEN tag_id = 3 THEN 'TAG3' END) AS ThirdTag,
max(CASE WHEN tag_id = 4 THEN 'TAG4' END) AS FourthTag,
max(CASE WHEN tag_id = 5 THEN 'TAG5' END) AS FifthTag
FROM questions_tags
GROUP BY question_id;

Grand total of Columns using Sum (if) in mysql

I am trying to calculate the grand total of columns I just created with a SUM (if). I have a table with several product numbers but I want to get totals for specific products only. This is my query:
Select date(orders.OrderDate) As Date,
Sum(If((orders.ProductNumber = '1'), orders.Qty, 0)) As `Product 1`,
Sum(If((orders.ProductNumber = '2'), orders.Qty, 0)) As `Product 2`,
Sum(If((orders.ProductNumber = '3'), orders.Qty, 0)) As `Product 3`,
From orders
Group By date(orders.OrderDate)
I get the totals for each product in columns as expected, but when I try to get the grand total (Product 1 + product 2 + Product 3) using Sum(orders.Qty) as Total, I get the SUM of ALL products in the table and not only the 3 I am looking for.
How can I get the SUM(Product 1 + Product 2 + Product 3)?
Thank you
Try this:
SELECT DATE(o.OrderDate) AS date,
SUM(IF(o.ProductNumber = '1', o.Qty, 0)) AS `Product 1`,
SUM(IF(o.ProductNumber = '2', o.Qty, 0)) AS `Product 2`,
SUM(IF(o.ProductNumber = '3', o.Qty, 0)) AS `Product 3`,
SUM(IF(o.ProductNumber IN ('1', '2', '3'), o.Qty, 0)) AS `Total`
FROM orders o
GROUP BY DATE(o.OrderDate)
Simply pre-cutting rows other than 1, 2, 3. This is faster when ProductNumber is INDEXed column.
SELECT DATE(orders.OrderDate) AS Date,
SUM(IF((orders.ProductNumber = '1'), orders.Qty, 0)) AS `Product 1`,
SUM(IF((orders.ProductNumber = '2'), orders.Qty, 0)) AS `Product 2`,
SUM(IF((orders.ProductNumber = '3'), orders.Qty, 0)) AS `Product 3`,
SUM(orders.Qty) AS Total
FROM orders
WHERE
orders.ProductNumber IN ('1', '2', '3')
GROUP BY DATE(orders.OrderDate)

MySQL SUM and CASE possible on DISTINCTROW?

I have this query :
SELECT
p.name,
COUNT(DISTINCT t.keyTask) AS totalTasksCount,
SUM(DISTINCT CASE WHEN t.keyPriority = 24 AND (t.keyState = 16 OR t.keyState = 17) THEN 1 ELSE 0 END) AS highPriorityTasksCount,
SUM(DISTINCT CASE WHEN t.keyState = 16 OR t.keyState = 17 THEN 1 ELSE 0 END) AS activesTasksCount,
SUM(DISTINCT t.estimatedDuration) AS estimatedDuration,
SUM(TIMESTAMPDIFF(SECOND,wp.start,wp.end)) * 1000 AS workedDuration
FROM projects_projects p
LEFT JOIN projects_tasks t
ON p.keyProject = t.keyProject
LEFT JOIN projects_workPeriods wp
ON wp.keyTask = t.keyTask
LEFT JOIN common_organizations o
ON o.keyOrganization = p.keyOrganization
LEFT JOIN common_users uc
ON uc.keyUser = p.keyUserCreator
LEFT JOIN common_users uu
ON uu.keyUser = p.keyUserUpdater
GROUP BY
p.keyProject
ORDER BY
highPriorityTasksCount DESC,
activesTasksCount DESC,
p.updated DESC,
p.name;
But the result fields highPriorityTasksCount and activesTasksCount returns 0 or 1 which is normal with this query. I was wondering if there is any way to make DISTINCTROW work on row and not on case result value for these fields without subquery ?
Current result :
p.name,
totalTasksCount,
highPriorityTasksCount,
activesTasksCount,
estimatedDuration,
workedDuration
'Project 1', '4', '1', '1', '14400000', '15300000'
'Project 2', '48', '1', '1', '84600000', '503100000'
'Project 3', '6', '1', '1', '108000000', NULL
'Project 4', '4', '1', '1', '25200000', '30600000'
'Project 5', '5', '1', '1', '226800000', '39600000'
'Project 6', '2', '0', '1', NULL, '10800000'
'Project 7', '9', '0', '1', NULL, '36900000'
Expected result :
'Project 1', '4', '1', '1', '14400000', '15300000'
'Project 2', '48','20', '2', '84600000', '503100000'
'Project 3', '6', '1', '1', '108000000', NULL
'Project 4', '4', '4', '2', '25200000', '30600000'
'Project 5', '5', '5', '1', '226800000', '39600000'
'Project 6', '2', '0', '1', NULL, '10800000'
'Project 7', '9', '0', '1', NULL, '36900000'
EDIT :
Modified query with subqueries since there is no way, help about optimization would be appreciated, this one is working :
SELECT
p.name,
COUNT(DISTINCT t.keyTask) AS totalTasksCount,
/* OLD SUM(DISTINCT CASE WHEN t.keyPriority = 24 AND (t.keyState = 16 OR t.keyState = 17) THEN 1 ELSE 0 END) AS highPriorityTasksCount, */
(
SELECT
SUM(CASE WHEN st.keyPriority = 24 AND (st.keyState = 16 OR st.keyState = 17) THEN 1 ELSE 0 END)
FROM projects_tasks st
WHERE
st.keyProject = p.keyProject
) AS highPriorityTasksCount,
/* OLD SUM(DISTINCT CASE WHEN t.keyState = 16 OR t.keyState = 17 THEN 1 ELSE 0 END) AS activesTasksCount, */
(
SELECT
SUM(CASE WHEN st.keyState = 16 OR st.keyState = 17 THEN 1 ELSE 0 END)
FROM projects_tasks st
WHERE
st.keyProject = p.keyProject
) AS activesTasksCount,
SUM(t.estimatedDuration) AS estimatedDuration,
SUM(TIMESTAMPDIFF(SECOND,wp.start,wp.end)) * 1000 AS workedDuration
FROM projects_projects p
LEFT JOIN projects_tasks t
ON p.keyProject = t.keyProject
LEFT JOIN projects_workPeriods wp
ON wp.keyTask = t.keyTask
LEFT JOIN common_organizations o
ON o.keyOrganization = p.keyOrganization
LEFT JOIN common_users uc
ON uc.keyUser = p.keyUserCreator
LEFT JOIN common_users uu
ON uu.keyUser = p.keyUserUpdater
GROUP BY
p.keyProject
ORDER BY
highPriorityTasksCount DESC,
activesTasksCount DESC,
p.updated DESC,
p.name;
without subquery.
No, you will have to use a subquery, or there's something I don't know about MySQL.