mysql - How to get if day past of any data in SELECT - mysql

I'm trying to make a summary making a indicator if any data in the SELECT past day from now... or just show a day (if > 0 : + , if < 0 : - ).
Like this: these are my tables.
We supose, today is 2013-12-25
tb_employee:
ID_EMP EMPLOYEE
1 Employee 1
2 Employee 2
3 Employee 3
tb_requirement:
ID_REQ REQUIREMENT
1 Requirement 1
2 Requirement 2
3 Requirement 3
4 Requirement 4
tb_detail:
ID_DET ID_EMP ID_REQ EXPIRATION
1 1 1 2013-12-29
2 1 2 2013-12-28
3 1 3 2013-12-31
4 2 2 2014-01-05
5 2 3 2013-12-20
6 2 4 2013-12-15
Now, the SELECT QUERY should show like this:
ID_EMP EMPLOYEE REQUIREMENTS_GOT ANY_REQ_EXPIRE
1 Employee 1 3 YES
2 Employee 2 3 NO
I hope i explained well. Maybe it could be with DATEDIFF ?
Thank you for answers... and of course, Merry Christmas !

Since you're trying to determine if any of the requirements expired, you should compare the minimal expiry date to today's date. There's no need to use datediff - a simple > operator packed in a case statement would do:
SELECT id_emp,
employee,
COUNT(*) AS requirements_got,
CASE WHEN CURDATE() > MIN(expiration) THEN 'yes' ELSE 'no' END AS any_req_expire
FROM tb_detail
JOIN tb_employee ON tb_detail.id_emp = tb_employee.id_emp
GROUP BY id_emp, employee

Related

SQL return latest data from each date

Sample table
id
id_sequence
date
1
1
2022-06-27
2
1
2022-06-27
3
1
2022-06-27
4
2
2022-06-27
5
2
2022-06-27
6
1
2022-06-28
7
1
2022-06-28
8
2
2022-06-28
9
2
2022-06-28
Expected Output
id
id_sequence
date
3
1
2022-06-27
5
2
2022-06-27
7
1
2022-06-28
9
2
2022-06-28
how can I make a query to get latest data on every date in MySql. tried to use MAX(id) for the id_sequence but it does not return a correct value since the expected output will take only highest id of every sequence and the output will only display distinct data of id_sequence 1,2 at date 2022-06-28.
If you want to make sure dates are taken distinctively, you need to add it inside the GROUP BY clause.
SELECT MAX(id) AS id,
id_sequence,
date_
FROM tab
GROUP BY id_sequence,
date_
ORDER BY id
Check the demo here.

Get last record from joined table

I have two tables DOCUMENT and SIGNATURES, like below
DOCUMENTS
doc_id doc_name
1 Contract
2 Lead
3 Invoice 1
4 Invoice 2
5 Payment 123
SIGNATURES
sig_id sig_doc_id signature_name
1 1 Paul
2 2 Mark
3 1 Chew
4 2 Paul
5 3 John
6 3 Derek
7 3 Silvan
8 5 Roden
And I'm try to get last signature name.
EXPECTED OUTPUT
doc_id doc_name signature_name
1 Contract Chew
2 Lead Paul
3 Invoice 1 Silvan
4 Invoice 2 < empty because we not have signature
5 Payment 123 Roden
I have a SQL FIDDLE with database and query, but when run search no record has found.
http://sqlfiddle.com/#!9/b98474/3
Here my query
SELECT docs.*, sign.*
FROM cnt_man_docs docs
INNER JOIN cnt_man_doc_signatures sign ON docs.cnt_man_doc_id = sign.cnt_man_doc_signature_doc_id
WHERE sign.cnt_man_doc_signature_id =
(SELECT MAX(cnt_man_doc_signature_id)
FROM cnt_man_doc_signatures
WHERE sign.cnt_man_doc_signature_id = docs.cnt_man_doc_id)
A simple method is a correlated subquery:
select d.*,
(select s.signature_name
from signatures s
where s.sig_doc_id = d.doc_id
order by s.sig_id desc
limit 1
) as signature_name
from documents d;
With an index on signatures(doc_id, sig_id desc, signature_name) this is probably the fastest method as well.

SQL - Max value from a group by when creating a new field

I have a database with a table called BOOKINGS containing the following values
main-id place-id start-date end-date
1 1 2018-8-1 2018-8-8
2 2 2018-6-6 2018-6-9
3 3 2018-5-5 2018-5-8
4 4 2018-4-4 2018-4-5
5 5 2018-3-3 2018-3-10
5 1 2018-1-1 2018-1-6
4 2 2018-2-1 2018-2-10
3 3 2018-3-1 2018-3-28
2 4 2018-4-1 2018-4-6
1 5 2018-5-1 2018-5-15
1 3 2018-6-1 2018-8-8
1 4 2018-7-1 2018-7-6
1 1 2018-8-1 2018-8-18
1 2 2018-9-1 2018-9-3
1 5 2018-10-1 2018-10-6
2 5 2018-11-1 2018-11-5
2 3 2018-12-1 2018-12-25
2 2 2018-2-2 2018-2-19
2 4 2018-4-4 2018-4-9
2 1 2018-5-5 2018-5-23
What I need to do is for each main-id I need to find the largest total number of days for every place-id. Basically, I need to determine where each main-id has spend the most time.
This information must then be put into a view, so unfortunately I can't use temporary tables.
The query that gets me the closest is
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT `BOOKINGS`.`main-id`, `BOOKINGS`.`place-id`, SUM(DATEDIFF(`end-date`, `begin-date`)) AS `total`
FROM `BOOKINGS`
GROUP BY `BOOKINGS`.`main-id`,`RESERVATION`.`place-id`
Which yields:
main-id place-id total
1 1 24
1 2 18
1 5 5
2 1 2
2 2 20
2 4 9
3 1 68
3 2 24
3 3 30
4 1 5
4 2 10
4 4 1
5 1 19
5 2 4
5 5 7
What I need is then the max total for each distinct main-id:
main-id place-id total
1 1 24
2 2 20
3 1 68
4 2 10
5 1 19
I've dug through a large amount of similar posts that recommend things like self joins; however, due to the fact that I have to create the new field total using an aggregate function (SUM) and another function (DATEDIFF) rather than just querying an existing field, my attempts at implementing those solutions have been unsuccessful.
I am hoping that my query that got me close will only require a small modification to get the correct solution.
Having hyphen character - in column name (which is also minus operator) is a really bad idea. Do consider replacing it with underscore character _.
One possible way is to use Derived Tables. One Derived Table is used to determine the total on a group of main id and place id. Another Derived Table is used to get maximum value out of them based on main id. We can then join back to get only the row corresponding to the maximum value.
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b1.main_id, b1.place_id, b1.total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS b1
JOIN
(
SELECT dt.main_id, MAX(dt.total) AS max_total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b2
ON b1.main_id = b2.main_id AND
b1.total = b2.max_total
MySQL 8+ solution would be utilizing the Row_Number() functionality:
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b.main_id, b.place_id, b.total
FROM
(
SELECT dt.main_id,
dt.place_id,
dt.total
ROW_NUMBER() OVER (PARTITION BY dt.main_id
ORDER BY dt.total DESC) AS row_num
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b
WHERE b.row_num = 1

Display two similar queries in one table

I'm trying to write a query which will return which garment generated the most revenue during the last three months compared to the same period last year.
I want to display the results in one table. The garment_id from the queries might match but might not. If it matches then I would like to display the results in the same row. I suppose I want to order by garment_id.
I have so far come up with this which almost works but returns incorrect/strange values for TotalDaysHired, MoneyIn, LastYrTotalDaysHired and LastYrMoneyIn; I've no idea why. I've also tried joining the two queries with an inner join ON a.garmentid = b.garmentid order by a.garmentid which wouldn't even run.
SELECT garment_hire_line.date_out as 'dateout',
garment_hire_line.garment_id as 'garmentid',
catalogue.description as 'description',
SUM(garment_hire_line.days) AS 'TotalDaysHired',
SUM(garment_hire_line.days*catalogue.daily_rate) AS 'MoneyIn',
'' as 'LastYrTotalDaysHired',
'' as 'LastYrMoneyIn'
FROM garment_hire_line
INNER JOIN garment ON garment_hire_line.garment_id = garment.garment_id
INNER JOIN catalogue ON garment.catalogue_id = catalogue.catalogue_id
WHERE garment_hire_line.date_out>DATE_SUB(NOW(),INTERVAL 3 MONTH)
GROUP by garment_hire_line.garment_id
UNION
SELECT garment_hire_line.date_out as 'dateout',
garment_hire_line.garment_id as 'garmentid',
catalogue.description as 'description','' as 'TotalDaysHired',
'' as 'MoneyIn',
SUM(garment_hire_line.days) AS 'LastYrTotalDaysHired',
SUM(garment_hire_line.days*catalogue.daily_rate) AS 'LastYrMoneyIn'
FROM garment_hire_line
INNER JOIN garment ON garment_hire_line.garment_id = garment.garment_id
INNER JOIN catalogue ON garment.catalogue_id = catalogue.catalogue_id
WHERE garment_hire_line.date_out<DATE_SUB(NOW(),INTERVAL 1 YEAR)
AND garment_hire_line.date_out>DATE_SUB(NOW(),INTERVAL '1:3' YEAR_MONTH)
GROUP by garment_hire_line.garment_id
garment_hire_line
garment_line_id date_out Days return_date discount hire_id garment_id
8 12/06/2012 4 16/06/2012 0 1 4
9 12/06/2012 5 17/06/2012 0 1 2
10 12/06/2012 4 16/06/2012 0 1 4
11 11/07/2012 3 14/07/2012 10 2 2
12 10/08/2012 3 13/08/2012 0 3 4
13 09/09/2012 2 11/09/2012 5 4 3
14 09/01/2017 3 12/09/2017 0 5 3
Catalogue
catalogue_id| description| designer| Type| daily_rate| supplier_name| supplier_purchase_price| date_purchased| quantity|
1 Hat Elizabeth Kate Accessory 3 Lids 25 28/02/2017 3
2 Dress Calvin Klein Designer Outfit 20 Glam 260 12/05/2012 2
3 Handbag Gucci Accessory 4 Hold On 200 01/01/2017 4
4 Witches Dress null Fancy Dress 12 Fancy Fred 74 21/05/2012 7
Garment
garment_id Colour sizing catalogue_id location_id supplier_id
1 Black Medium 1 2 1
2 Black 10 2 2 2
3 Black 8 2 2 3
4 Black 0 3 2 4
5 Red Child 4 2 1
6 Black Medium 1 2 2
7 Black 10 2 2 3
The main issue is that in your SQL query you use '' for some fields that really are supposed to return numerical data. So you get some records with '' and 3.00 in the same column, which is a conflict in data type. This causes some undesired conversions leading to the garbage output you saw.
Fix this by replacing '' with null.
But you might also want to look into some other issues:
As you group by the garment ID, you have no control over which date is being displayed in the first column when a particular garment was hired multiple times in the same period.
In fact this query would not be valid in newer versions of MySql (unless you set an option to allow it) and violates standard SQL rules. So you should either remove that column from the query, or apply an aggregation function to it (like MAX), or group by it.
By using a union you will not really take advantage of showing the two periods side-by-side: 2 out of the 4 fields in one record will always be null. You can do this without union and filter what you sum up with an expression in the sum aggregate function.
So I would suggest this query:
SELECT MAX(garment_hire_line.date_out) as `LastDateOut`,
garment_hire_line.garment_id as `garmentid`,
catalogue.description as `description`,
SUM(CASE WHEN garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days
ELSE 0
END) AS `TotalDaysHired`,
SUM(CASE WHEN garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days*catalogue.daily_rate
ELSE 0
END) AS `MoneyIn`,
SUM(CASE WHEN garment_hire_line.date_out <= DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days
ELSE 0
END) AS `LastYrTotalDaysHired`,
SUM(CASE WHEN garment_hire_line.date_out <= DATE_SUB(NOW(),INTERVAL 3 MONTH)
THEN garment_hire_line.days*catalogue.daily_rate
ELSE 0
END) AS `LastYrMoneyIn`
FROM garment_hire_line
INNER JOIN garment ON garment_hire_line.garment_id = garment.garment_id
INNER JOIN catalogue ON garment.catalogue_id = catalogue.catalogue_id
WHERE garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 3 MONTH)
OR ( garment_hire_line.date_out > DATE_SUB(NOW(),INTERVAL 15 MONTH)
AND garment_hire_line.date_out < DATE_SUB(NOW(),INTERVAL 12 MONTH)
)
GROUP BY garment_hire_line.garment_id
ORDER BY 1
If you prefer to have a separate line for each date, then remove the MAX function, but add garment_hire_line.date_out in the GROUP BY list.

mysql count with aritmmetic operation with condition

I have two tables.
job_table.
job_id job_type job_type *****
1 1 Day *****
2 2 Night
3 3 Day & Night.
4 3 Day & Night.
and task_entry table.
task_entry_id job_type task_option_type
1 1 Day
2 1 Day
3 1 Day
4 2 Night
5 3 Day
6 3 Night
7 3 Day
8 3 Night
If job id is 3 then there will be 2 entries one for Day and one for Night.
Else only one entry.
I want to get the total count of jobs with task_entries like this,
job_id task_entry_count
1 3
2 1
3 2
That is if job_type is 3 then count should be count/2. (Day&Night).
Else count should be normal count.
You can JOIN the two tables together and then use GROUP BY to get the number of total count of jobs.
SELECT jt.job_id,
ROUND(SUM (CASE WHEN jt.job_type = 3 THEN 0.5 ELSE 1 END), 0) AS task_entry_count
FROM job_table jt INNER JOIN task_entry te
ON jt.job_type = te.job_type
GROUP BY jt.job_id