SQL nested select sum returns wrong integer - mysql

I have the following select statement:
SELECT
T.name,
C.name as competence_name,
THC.competence_level_id as requiredLevel,
(SELECT SUM(UHC.competence_level_id) FROM user_has_competence UHC INNER JOIN user U ON U.id = UHC.user_id WHERE competence_id = C.id AND U.title_id = T.id GROUP BY T.id) as current_level,
(SELECT
ROUND(SUM(UHC.competence_level_id)/ COUNT(UHC.user_id))
FROM
user_has_competence UHC
JOIN user U ON U.id = UHC.user_id
WHERE
competence_id = C.id
AND U.title_id = T.id GROUP BY T.id) - THC.competence_level_id as gap,
C.id
FROM
title_has_competence THC
JOIN
title T ON T.id = THC.title_id
JOIN
competence C ON C.id = THC.competence_id
This returns the following result:
'Head of IT', 'Office', '7', '16', '1', '524'
'Head of IT', 'Empatisk', '2', '5', '1', '527'
'Head of IT', 'Målrettet', '5', '12', '1', '529'
'Head of IT', 'Udadvendt', '10', NULL, NULL, '525'
'Webudvikler', 'Office', '2', '3', '1', '524'
'Webudvikler', 'Outlook', '3', '4', '1', '526'
'Webudvikler', 'Målrettet', '6', '10', '4', '529'
'Webudvikler', 'Back-end', '9', '9', '0', '534'
'Webudvikler', 'Infosoft', '10', '5', '-5', '532'
However the result is invalid:
In the first row you will see the current level sum is = 16 this should be 9 (6 + 3)
The gap is also incorrect as the gap should be 9 / 2 = 4.5 - 7 = -2.5
So my question is what am i doing wrong? why is my SUM() function returning way to much.
Also note that the COUNT() returns the right value = 2
The Tables
title_has_competence
id title_id competence_id competence_level_id
'82', '165', '527', '2'
'85', '166', '524', '2'
'86', '166', '526', '3'
'83', '165', '529', '5'
'87', '166', '529', '6'
'81', '165', '524', '7'
'88', '166', '534', '9'
'84', '165', '525', '10'
'89', '166', '532', '10'
User_has_competence
user_id, competence_id, competence_level_id, progression
'1', '524', '6', '0'
'1', '527', '4', '0'
'1', '529', '3', '0'
'2', '524', '10', '0'
'2', '527', '1', '0'
'2', '529', '9', '0'
'3', '524', '3', '0'
'3', '526', '4', '0'
'3', '529', '10', '0'
'3', '532', '5', '0'
'3', '534', '9', '0'
title
id, name organization_id
'165', 'Head of IT', '1'
'166', 'Webudvikler', '1'
User
id, username, password, title_id,
1 ** , ** , 165
2 ** , ** , 165
3 ** , ** , 166

Related

SQL query to get number of clients with last statement equal connected

I need to make a SQL query
table 'records' structure:
contact_id(integer),
client_id(integer),
worker_id(integer),
statement_status(varchar),
contact_ts(timestamp)
It has to show the following:
current date
number of clients which last statement_status was 'interested'
number of clients which last statement_status was 'not_interested' and previus status was 'not_present'
Could somebody help?
sample data:
contact_id client_id contact_ts worker_id statement_status
'1', '181', '2017-09-24 03:38:31.000000', '107', 'voicemail'
'2', '72', '2017-09-23 09:32:38.000000', '10', 'not_interested'
'3', '277', '2017-09-22 07:06:16.000000', '119', 'interested'
'4', '36', '2017-09-21 04:39:57.000000', '118', 'not_present'
'5', '33', '2017-09-20 04:12:12.000000', '161', 'voicemail'
'6', '244', '2017-09-19 02:26:30.000000', '13', 'not_interested'
'7', '346', '2017-09-18 02:30:35.000000', '255', 'interested'
'8', '128', '2017-09-17 06:20:13.000000', '52', 'not_present'
'9', '33', '2017-09-16 08:58:02.000000', '188', 'not_present'
'10', '352', '2017-09-15 08:18:40.000000', '324', 'not_interested'
'11', '334', '2017-09-14 04:27:40.000000', '373', 'interested'
'12', '2', '2017-09-13 08:44:40.000000', '40', 'not_present'
'13', '33', '2017-09-12 03:46:16.000000', '252', 'voicemail'
'14', '366', '2017-09-11 04:31:22.000000', '78', 'not_interested'
'15', '184', '2017-09-10 06:08:01.000000', '289', 'interested'
'16', '184', '2017-09-09 05:45:56.000000', '124', 'not_present'
'17', '102', '2017-09-08 07:09:30.000000', '215', 'voicemail'
'18', '140', '2017-09-07 08:09:18.000000', '196', 'not_interested'
'19', '315', '2017-09-06 05:13:40.000000', '242', 'interested'
'20', '268', '2017-09-05 07:41:40.000000', '351', 'not_present'
'21', '89', '2017-09-04 05:32:05.000000', '232', 'voicemail'
desired output:
Time, interested, not-interested
2017-09-10 06:08:01, 5, 5
I tried something with sub queries, but it obviously doesn't work:
SELECT
GETDATE()
,(select count(*)
from record a
where (select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 1) == "interested"
group by a.contact_id)
,(select count(*)
from record a
where (select (select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 2) order by a.contact_ts desc limit 1) == "interested"
and
(select statement_status
from record
where client_id == a.client_id
order by a.contact_ts
limit 1) == "interested"
group by a.contact_id)
from record b;
How should I use the inner selects?
I must write a poem, because most of my post is a code.
So maybe something from "Dead man"?
“Don't let the sun burn a hole in your ass, William Blake. Rise now, and drive your cart and plough over the bones of the dead!”
;)
Try something like this:
WITH status AS (
SELECT DISTINCT client_id,
first_value(statement_status) OVER w1 AS last_status,
nth_value(statement_status, 2) OVER w1 AS prev_status
FROM records
WINDOW w1 AS (PARTITION BY client_id ORDER BY contact_ts DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
)
SELECT CURRENT_DATE(),
SUM(last_status = 'interested') AS interesed,
SUM(last_status = 'not_interested' AND prev_status = 'not_present') AS not_interested
FROM status

MySQL count(*) returning 0 even though I used IFNULL and COALESCE

Here is my query:
USE adventureWorks4mysql;
SELECT DISTINCT a.city, count(a.city) as "City Count", emp.Gender as Gender, emp.VacationHours as VacationHours,
(select if(count(*) is null,0, count(*))
FROM address aa
inner join employeeaddress empad on aa.AddressID = empad.AddressID
inner join employee emp on empad.EmployeeID = emp.EmployeeID
where MaritalStatus = 'M' and aa.city = a.city
group by aa.City) as married,
(select ifnull(count(*),0)
FROM address aa
inner join employeeaddress empad on aa.AddressID = empad.AddressID
inner join employee emp on empad.EmployeeID = emp.EmployeeID
where MaritalStatus = 'S' and aa.city = a.city
group by aa.City) as single
FROM address a
inner join employeeaddress empad on a.AddressID = empad.AddressID
inner join employee emp on empad.EmployeeID = emp.EmployeeID
group by a.City;
returns the following:
'Bellevue', '36', 'F', '5', '22', '14'
'Berlin', '1', 'F', '35', NULL, '1'
'Bordeaux', '1', 'M', '34', NULL, '1'
'Bothell', '13', 'M', '9', '7', '6'
'Calgary', '1', 'M', '33', '1', NULL
'Cambridge', '2', 'F', '37', '2', NULL
'Carnation', '5', 'M', '77', '4', '1'
'Detroit', '1', 'M', '38', NULL, '1'
'Duluth', '1', 'F', '24', NULL, '1'
'Duvall', '10', 'F', '80', '3', '7'
'Edmonds', '25', 'M', '84', '16', '9'
'Everett', '18', 'M', '42', '11', '7'
'Gold Bar', '5', 'M', '92', '3', '2'
'Index', '5', 'F', '61', '3', '2'
'Issaquah', '15', 'M', '70', '4', '11'
'Kenmore', '12', 'F', '86', '5', '7'
'Kent', '1', 'F', '5', '1', NULL
'Melbourne', '1', 'F', '36', NULL, '1'
'Memphis', '1', 'M', '29', '1', NULL
'Minneapolis', '1', 'M', '48', NULL, '1'
'Monroe', '14', 'M', '21', '4', '10'
'Nevada', '1', 'F', '27', '1', NULL
'Newport Hills', '7', 'M', '44', '2', '5'
'Ottawa', '1', 'M', '31', '1', NULL
'Portland', '1', 'F', '22', NULL, '1'
'Redmond', '21', 'M', '2', '11', '10'
'Renton', '17', 'M', '6', '12', '5'
'Sammamish', '17', 'F', '31', '6', '11'
'San Francisco', '2', 'M', '16', '2', NULL
'Seattle', '44', 'F', '82', '21', '23'
'Snohomish', '10', 'M', '88', '3', '7'
Not at all clear about you desired result, but is you are attempting to count cities, then I suggest you use "conditional aggregates" instead of your current approach, like this:
SELECT
a.city
, COUNT( a.city ) AS "City Count"
, count(CASE WHEN maritalstatus = 'M' THEN a.city END) AS married
, count(CASE WHEN maritalstatus = 'S' THEN a.city END) AS single
FROM address a
INNER JOIN employeeaddress empad ON a.addressid = empad.addressid
INNER JOIN employee emp ON empad.employeeid = emp.employeeid
GROUP BY
a.city;
Note how the case expression is INSIDE the aggregate function COUNT - hence the term "conditional aggregates" e.g. for singles, if there is a singe status then count that address other wise just ignore that row. nb COUNT does not increment if a value is null.
Please also note that you are only grouping by the single column city. If you really want more result rows because of gender and vacationhours then also use those columns in the GROUP BY clause
SELECT
a.city
, emp.gender AS Gender
, emp.vacationhours AS VacationHours
, COUNT( a.city ) AS "City Count"
, count(CASE WHEN maritalstatus = 'M' THEN a.city END) AS married
, count(CASE WHEN maritalstatus = 'S' THEN a.city END) AS single
FROM address a
INNER JOIN employeeaddress empad ON a.addressid = empad.addressid
INNER JOIN employee emp ON empad.employeeid = emp.employeeid
GROUP BY
a.city
, emp.gender
, emp.vacationhours
;

Add extra shop filters based on the current selection

I have the following table (MySQL database, table products_attributes):
product_id|attribute_id|attribute_value_id
I have the current products IDs (filtered by a category or a search query) that I can use to filter the table; this will make sure I will build all of the available filters based on the current filtered products.
My problem is that I have to build the filters list based on the current products and be able to add some extra ones that will allow me to expand the results; those filters will come from products that have at least n-1 of the applied filters; the n filter will be the extra one.
Example:
I'm on Shoes category and filtering by color (black) and size (40); in my filters list I got now Color: Black and Size: 40 (as filtered); in this case I also have products that have the color black but the size is 42; I need the 42 to be shown in the Size filter as a viable option as this respects the n-1 rule for additional filters.
I don't know how to do this in one SQL query. The idea is too look in the table for a product_id that has at least n-1 of the selected filters as attribute_value_id; the results should be an unique collection of attributes_values_ids that contain the current filters and the extra viable ones.
Maybe this is more useful:
This is my filtering criteria (attribute_id, attribute_value_id): (1, 12) and (6, 268).
This means that the filters list will be made from all of the filtered products but without extra viable options. If I run this, then I will have, in this case, all the products belonging to the current category:
QUERY:
select * from product_attributes
where product_id in (812,813,814,815,816,817,818,819,820,1361,1362,1465,1466,1582,1583,1784,1794,1795,1802);
RESULTS
# product_id, attribute_id, attribute_value_id
'812', '1', '12'
'812', '2', '13'
'812', '6', '139'
'813', '1', '12'
'813', '2', '13'
'813', '6', '249'
'814', '1', '12'
'814', '2', '13'
'814', '6', '268'
'815', '1', '12'
'815', '2', '13'
'815', '6', '249'
'816', '1', '12'
'816', '2', '13'
'816', '6', '249'
'817', '1', '12'
'817', '2', '13'
'817', '6', '268'
'818', '1', '12'
'818', '2', '13'
'818', '6', '249'
'819', '1', '12'
'819', '2', '277'
'819', '6', '310'
'820', '1', '12'
'820', '2', '13'
'820', '6', '93'
'1361', '1', '12'
'1361', '2', '36'
'1362', '1', '12'
'1465', '1', '12'
'1465', '2', '13'
'1465', '6', '249'
'1466', '1', '12'
'1466', '2', '13'
'1466', '6', '268'
'1582', '1', '12'
'1582', '2', '277'
'1582', '6', '139'
'1583', '1', '12'
'1583', '2', '277'
'1583', '6', '516'
'1784', '1', '12'
'1784', '2', '13'
'1784', '6', '139'
'1794', '1', '12'
'1794', '2', '13'
'1794', '6', '93'
'1802', '1', '12'
'1802', '2', '66'
'1802', '6', '93'
If I apply the filters (1, 12) and (6, 268) then only this products will remain: 814, 817, 1466
What I want to get as a result:
The product with the ID of 812 has combinations of (1, 12), (2, 13), (6, 139); Because I am applying a filtering combination of (1, 12) and (6, 268) this product has the n-1 combinations of filters so the 139 should be added to the filters list as a new, viable option.
This is the code that I'm using in order to generate the SQL:
$wheres = [];
foreach ($this->appliedFilters as $attributeId => $attributeValuesIds) {
foreach ($attributeValuesIds as $attributeValueId) {
$wheres[] = "attribute_id = {$attributeId} and attribute_value_id = {$attributeValueId}";
}
}
$filteredSql = "SELECT * FROM product_attributes WHERE product_id IN (".implode(',', $this->filteredProductsIds).")";
$filtersSql = 'SELECT * FROM product_attributes WHERE product_id IN (SELECT DISTINCT product_id FROM product_attributes';
$firstWhere = array_shift($wheres);
$filtersSql .= " WHERE ({$firstWhere})";
foreach ($wheres as $where) {
$filtersSql .= " OR ({$where})";
}
$filtersSql .= ')';
$mergedSql = "
SELECT A.attribute_value_id, A.attribute_id FROM ({$filteredSql}) as A
INNER JOIN ({$filtersSql}) AS B ON B.product_id = A.product_id";
echo "$filteredSql$filtersSql$mergedSql";
The SQL outputed are:
SELECT * FROM product_attributes WHERE product_id IN (812,813,814,815,816,817,818,819,820,1361,1362,1465,1466,1582,1583,1784,1794,1795,1802)
SELECT * FROM product_attributes WHERE product_id IN (SELECT DISTINCT product_id FROM product_attributes WHERE (attribute_id = 1 and attribute_value_id = 12) OR (attribute_id = 2 and attribute_value_id = 277))
SELECT A.attribute_value_id, A.attribute_id FROM (SELECT * FROM product_attributes WHERE product_id IN (812,813,814,815,816,817,818,819,820,1361,1362,1465,1466,1582,1583,1784,1794,1795,1802)) as A INNER JOIN (SELECT * FROM product_attributes WHERE product_id IN (SELECT DISTINCT product_id FROM product_attributes WHERE (attribute_id = 1 and attribute_value_id = 12) OR (attribute_id = 2 and attribute_value_id = 277))) AS B ON B.product_id = A.product_id
The result of the final SQL is:
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'12', '1'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'13', '2'
'36', '2'
'36', '2'
'66', '2'
'66', '2'
'66', '2'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'93', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'139', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'249', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'268', '6'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'277', '2'
'310', '6'
'310', '6'
'310', '6'
'516', '6'
'516', '6'
'516', '6'
Values like 23/249 are invalid values for the products being returned. I get the extra values I need but I also get those.
All you need to do in your example query is to replace the list of product id's with a sub-query.
SELECT *
FROM product_attributes
WHERE product_id IN
(
SELECT DISTINCT product_id
FROM product_attributes
WHERE (
attribute_id='a'
AND attribute_value_id='x')
OR (
attribute_id='b'
AND attribute_value_id='y') ;

SQL query to show top x records with evenly distributed values

I have a database of contacts at companies. Multiple contacts per company in different departments. Each company has turnover and industry data attached to it.
I need to write a query that shows the top 10 most recently added contacts (unix timestamp) but i don't want it to be all Marketing contacts (even if the top 10 are), i would like to look at the top 100 instead and get 10 contacts out that are from different departments. So instead of the top 10 being all marketing, there might be 2 marketing, 2 I.T, 2 HR, 2 Personnel.
So my query basically is this:
SELECT DISTINCT `surname`, `job_title`, `company_name`
FROM (`company_database`)
WHERE `employee_code` IN ('6', '7', '8', '9', '10', '11', '12', '13')
AND `turnover_code` IN ('5', '6', '7', '8')
AND `contact_code` IN ('16', '17', '26', '27', '9', '10', '30', '31', '23', '24', '12', '13') AND `industry_code` NOT IN ('22', '17', '35', '36') LIMIT 10
But that simply returns a unique row. What i need is one contact per company and no more than 1 contact_code type. I also only want 10 rows returned, but obviously to get this 1 per contact code per row, the query will need to look at more than 10.
Is this possible in just a query? Or should i do something programatically to apply the logic needed to whittle down the results of a query.
you can work with a temporary table using the myisam engine and a trick.
If you create the following temporary table:
create table tmp_company_sequence
( surname varchar(255)
,job_title varchar(255)
,company_name varchar(255)
,date_added date
,contact_code int
,counter int auto_increment
,primary key (contact_code,counter)
);
Now
insert into `tmp_company_sequence`( `surname`, `job_title`, `company_name`,`contact_code`,`date_added`)
SELECT DISTINCT `surname`, `job_title`, `company_name`,`contact_code`,`date_added`
FROM (`company_database`)
WHERE `employee_code` IN ('6', '7', '8', '9', '10', '11', '12', '13')
AND `turnover_code` IN ('5', '6', '7', '8')
AND `contact_code` IN ('16', '17', '26', '27', '9', '10', '30', '31', '23', '24', '12', '13') AND `industry_code` NOT IN ('22', '17', '35', '36')
order by contact_code, added_date desc;
Your temporary table will now hold all the contacts with a counter. The counter is increased for every contact of the same contact_code. SO the newest contact with a certain contact code will have counter = 1, the next recent will have counter = 2 and so on.
You can now do a
select *
from tmp_company_sequence
order by counter asc, date_added desc
limit 10;
This will give you a list of the latest contacts added over all contact_codes.
Edit:
I just realised this could be done with a single query, but it is even more ugly:
SELECT `surname`
, `job_title`
, `company_name`
, `contact_code`
FROM(
SELECT
`surname`
, `job_title`
, `company_name`
, `contact_code`
, `date_added`
, IF(contact_code = #prev_contact_code,#i:=#i+1,#i:=1) AS counter
, #prev_contact_code = contact_code
FROM
(`company_database`)
,(SELECT #i := 1)
WHERE `employee_code` IN ('6', '7', '8', '9', '10', '11', '12', '13')
AND `turnover_code` IN ('5', '6', '7', '8')
AND `contact_code` IN (
'16'
, '17'
, '26'
, '27'
, '9'
, '10'
, '30'
, '31'
, '23'
, '24'
, '12'
, '13'
)
AND `industry_code` NOT IN ('22', '17', '35', '36')
ORDER BY contact_code
, added_date DESC) sub
WHERE counter = 1
ORDER BY added_date DESC
LIMIT 10;
This does basically the same as the option with the temporary table, but it creates the counter in the fly by storing data from the previous column in global variables. It is messy but can be used within a single query.

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.