How do we select non-aggregate columns in a query with a GROUP BY clause, which is not functionally dependent on columns in GROUP BY clause? - mysql

My SQL
SELECT
`tbl_order`.`order_id`
FROM `tbl_order`
LEFT JOIN `tbl_rooms` ON `tbl_order`.`room_name` = `tbl_rooms`.`room_id`
LEFT JOIN `tbl_orderdetails` ON `tbl_order`.`order_key` = `tbl_orderdetails`.`orderdetail_orderkey`
LEFT JOIN `tbl_guestcatlang` ON `tbl_order`.`order_product_type`=`tbl_guestcatlang`.`guestcatlang_guestcat_id`
and `tbl_guestcatlang`.`guestcatlang_lang_id`="en"
JOIN `tbl_sitesettings` ON `tbl_order`.`order_setting_id` = `tbl_sitesettings`.`setting_id`
WHERE
(
(
tbl_sitesettings.delayedBrekfast = 1 AND
`tbl_order`.`order_product_type` = "BREAKFAST" AND
(
`tbl_order`.`order_required_time` > "2018-02-28 18:30:00" AND
`tbl_order`.`order_required_time` < "2018-03-01 18:29:59" AND
tbl_sitesettings.delayTime - (unix_timestamp(convert_tz(now(),("UTC"), tbl_sitesettings.timeZone))-unix_timestamp()) < "26100"
)
) OR
(
`tbl_sitesettings`.`delayedBrekfast` != 1 OR
`tbl_order`.`order_status` = "Complete" OR
tbl_order.order_product_type != "BREAKFAST"
)
) AND
`tbl_order`.`order_status` IN('Open') AND
`tbl_order`.`order_product_type` IN('BREAKFAST', 'Room Service', 'AMENITIES', 'GIFT SHOP', 'Internet Plan', 'Device Management',
'System Message', '70', '69', '67', '68', '75', '76', '77', '78',
'93', '94', '95', '97', '98', '101', '102', '103', '104', '105',
'106', '107', '108', '109', '110', '111', '112', '113', '114', '115',
'116', '117', '118', '119', '120', '121', '122', '123', '124', '127',
'128', '135') AND
`tbl_order`.`order_product_type` != 'Recomended Product' AND
`tbl_order`.`order_setting_id` = '7'
GROUP BY `tbl_order`.`order_key`
ORDER BY `tbl_order`.`ordered_time` DESC
And this was the error Message
Expression #1 of SELECT list is not in GROUP BY clause and contains
nonaggregated column 'ebdb_production.tbl_order.order_id' which is not
functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
Any solution ??? :(

Try execute the below query. This will remove the restriction of such.
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));

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
;

SELECT from table AND 'archive' table at once

To reduce the size of one of our tables (currently over 4 million rows), I've created an 'archive' table which will only be accessed by certain users.
The archive table is a replica of the main table, except it has OLD rows in it that are rarely accessed.
However, sometimes I'll need to query both tables:
SELECT
t1.*,
t6.*
FROM (
SELECT
COUNT(DISTINCT up.lesson_id) AS assessment_count,
MIN(up.date) AS first_date,
MAX(up.date) AS last_date
FROM
cdu_user_progress up
WHERE
(up.game_id = '0') AND
(up.uid = '150') AND
(up.lesson_id IN ('65', '1112', '66', '67', '68', '69', '1114', '70', '71', '72', '73', '74', '75', '1113', '77', '424', '423', '1115', '93', '94', '95', '420', '421', '422', '96', '97', '98', '99', '100', '101', '1015', '102', '415', '104', '106', '105', '107', '108', '1016', '109', '110', '160', '111', '113', '112', '738', '739', '1050', '1051', '116', '117', '118', '119', '120', '121', '1017', '123', '124', '125', '130', '1018', '131', '148', '149', '150', '151', '152', '153', '154', '155', '156', '157', '158', '159', '171', '172', '173', '174', '175', '176', '177', '178', '179', '180', '181', '182', '267', '268', '269', '270', '271', '272', '273', '274', '1019', '278', '775', '279', '280', '281', '282', '283', '284', '285', '286', '1161', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', '297', '298', '299', '300', '301', '318', '319', '302', '303', '304', '305', '306', '307', '308', '309', '337', '338', '339', '340', '341', '342', '343', '344', '345', '346', '1054', '347', '348', '349', '350', '351', '352', '353', '354', '355', '356', '377', '378', '379', '380', '479', '480', '481', '482', '431', '432', '433', '434', '435', '436', '437', '438', '439', '440', '441', '442', '443', '444', '445', '446', '448', '447', '449', '450', '451', '452', '453', '454', '456', '455', '457', '458', '459', '460', '461', '462', '463', '464', '465', '466', '467', '468', '469', '470', '471', '472', '473', '474', '475', '476', '477', '478', '1090')) AND
(up.score > '-1')
) t1
INNER JOIN (
SELECT
AVG(c1.score) AS avg_first_scores,
SUM(c1.score) AS sum_first_scores
FROM
cdu_user_progress c1
LEFT OUTER JOIN cdu_user_progress c2 ON c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1
WHERE
(c1.game_id = '0') AND
(c1.uid = '150') AND
(c1.lesson_id IN ('65', '1112', '66', '67', '68', '69', '1114', '70', '71', '72', '73', '74', '75', '1113', '77', '424', '423', '1115', '93', '94', '95', '420', '421', '422', '96', '97', '98', '99', '100', '101', '1015', '102', '415', '104', '106', '105', '107', '108', '1016', '109', '110', '160', '111', '113', '112', '738', '739', '1050', '1051', '116', '117', '118', '119', '120', '121', '1017', '123', '124', '125', '130', '1018', '131', '148', '149', '150', '151', '152', '153', '154', '155', '156', '157', '158', '159', '171', '172', '173', '174', '175', '176', '177', '178', '179', '180', '181', '182', '267', '268', '269', '270', '271', '272', '273', '274', '1019', '278', '775', '279', '280', '281', '282', '283', '284', '285', '286', '1161', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', '297', '298', '299', '300', '301', '318', '319', '302', '303', '304', '305', '306', '307', '308', '309', '337', '338', '339', '340', '341', '342', '343', '344', '345', '346', '1054', '347', '348', '349', '350', '351', '352', '353', '354', '355', '356', '377', '378', '379', '380', '479', '480', '481', '482', '431', '432', '433', '434', '435', '436', '437', '438', '439', '440', '441', '442', '443', '444', '445', '446', '448', '447', '449', '450', '451', '452', '453', '454', '456', '455', '457', '458', '459', '460', '461', '462', '463', '464', '465', '466', '467', '468', '469', '470', '471', '472', '473', '474', '475', '476', '477', '478', '1090')) AND
(c1.score > '-1') AND
(c2.date IS '')
) t6
The solutions I've already thought of - replace SELECT cdu_user_progress with a nested-query:
SELECT * FROM cdu_user_progress UNION SELECT * FROM cdu_user_progress_archive
But this would create a huge temporary table in memory.
I tried UNION of each query (nested queries above), but this results in multiple rows returned, where it used to return a single row.
SELECT
...
FROM (
SELECT
...
FROM
cdu_user_progress up
WHERE
...
UNION SELECT
...
FROM
cdu_user_progress_archive up
WHERE
...
) t1
INNER JOIN (
SELECT
...
FROM
cdu_user_progress c1
LEFT OUTER JOIN cdu_user_progress c2 ON c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1
WHERE
...
UNION SELECT
...
FROM
cdu_user_progress_archive c1
LEFT OUTER JOIN cdu_user_progress_archive c2 ON c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1
WHERE
...
) t6
Any other ideas???
Thanks!
Those suq-queries contain aggregates.
So a simple solution is to sin against the DRY principle (Don't Repeat Yourself).
I.e. copy&paste those queries, change to the archive tables and union them.
But that list of lesson_id's is rather long.
Probably better to put those in a temp table so it can be reused.
SELECT t1.*, t6.*
FROM (
SELECT 'current' as Src,
COUNT(DISTINCT up.lesson_id) AS assessment_count,
MIN(up.date) AS first_date,
MAX(up.date) AS last_date
FROM cdu_user_progress up
INNER JOIN temp_lessonid_list lst
ON lst.lesson_id = up.lesson_id
WHERE up.game_id = 0
AND up.uid = 150
AND up.score > -1
UNION ALL
SELECT 'archive' as Src,
COUNT(DISTINCT up.lesson_id) AS assessment_count,
MIN(up.date) AS first_date,
MAX(up.date) AS last_date
FROM cdu_user_progress_archive up
INNER JOIN temp_lessonid_list lst
ON lst.lesson_id = up.lesson_id
WHERE up.game_id = 0
AND up.uid = 150
AND up.score > -1
) t1
INNER JOIN
(
SELECT 'current' as Src,
AVG(c1.score) AS avg_first_scores,
SUM(c1.score) AS sum_first_scores
FROM cdu_user_progress c1
INNER JOIN temp_lessonid_list lst
ON lst.lesson_id = c1.lesson_id
LEFT JOIN cdu_user_progress c2
ON (c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1)
WHERE c1.game_id = 0
AND c1.uid = 150
AND c1.score > -1
AND c2.date IS ''
UNION ALL
SELECT 'archive' as Src,
AVG(c1.score) AS avg_first_scores,
SUM(c1.score) AS sum_first_scores
FROM cdu_user_progress_archive c1
INNER JOIN temp_lessonid_list lst
ON lst.lesson_id = c1.lesson_id
LEFT JOIN cdu_user_progress_archive c2
ON (c1.uid = c2.uid AND c1.lesson_id = c2.lesson_id AND c1.game_id = c2.game_id AND c1.level = c2.level AND c1.date > c2.date AND c2.score > -1)
WHERE c1.game_id = 0
AND c1.uid = 150
AND c1.score > -1
AND c2.date IS ''
) t6 ON t6.Src = t1.Src;
You could also research table partitioning.
you can write 2 separate queries for each table and use the mysql UNION keyword to join them together
eg
(SELECT * FROM table1 WHERE col="value")
UNION
(SELECT * FROM table2 WHERE col="value");
https://dev.mysql.com/doc/refman/8.0/en/union.html

Joining of two tables is not working

I have 2 tables. Table1 and Table2.
Table1 data:
Id org_id start_date end_date month
'1', '46', '2015-01-01', '2015-01-31', 'January'
'2', '46', '2015-02-01', '2015-02-28', 'February'
'3', '46', '2015-03-01', '2015-03-31', 'March'
'4', '46', '2015-04-01', '2015-04-30', 'April'
'5', '46', '2015-05-01', '2015-05-31', 'May'
'6', '46', '2015-06-01', '2015-06-30', 'June'
'7', '46', '2015-07-01', '2015-07-31', 'July'
'8', '46', '2015-08-01', '2015-08-31', 'August'
'9', '46', '2015-09-01', '2015-09-30', 'September'
'10', '46', '2015-10-01', '2015-10-31', 'October'
'11', '46', '2015-11-01', '2015-11-30', 'November'
'12', '46', '2015-12-01', '2015-12-31', 'December'
Table2 data:
Id org_id from_date emp_id
'48', '46', '2015-06-09' 1
'49', '46', '2015-06-09' 1
'50', '46', '2015-06-01' 2
'51', '46', '2015-05-20' 1
'56', '46', '2015-07-07' 2
This is my query:
select t1.month,count(t2.emp_id) as count
from Table1 t1
left outer join Table2 t2 on t2.from_date between t1.start_date and t1.end_date
where t2.org_id=46 group by t1.month
Output i am getting is:
month count
'July', '1'
'June', '3'
'May', '1'
Output i am expecting is:
month count
'January', '0'
'February', '0'
'March', '0'
'April', '0'
'May', '1'
'June', '3'
'July', '1'
'August', '0'
'September', '0'
'October', '0'
'November', '0'
'December', '0'
I have used left outer join. But all records from left table is not getting fetched.
Any help!!
You have to put the part of your wherestatament to the on clase:
select t1.month,count(t2.emp_id) as count
from Table1 t1
left outer join Table2 t2 on t2.from_date between t1.start_date and t1.end_date
and t2.org_id=46 group by t1.month
If you do not do it you have a inner join
try this..
SELECT t1.month,COUNT(t2.emp_id) AS COUNT
FROM Table1 t1
LEFT JOIN Table2 t2 ON t2.from_date BETWEEN t1.start_date AND t1.end_date
AND t2.org_id=46 GROUP BY t1.month

SQL nested select sum returns wrong integer

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