Generate resultset according to report - mysql

How do I generate the following reports using MYSQL?
My table 'reservations' looks like this:
id | arrival | created.
1 | 2014-3-30 | 2014-3-1
2 | 2014-3-31 | 2014-3-2
3 | 2014-3-28 | 2014-3-2
4 | 2014-3-01 | 2014-3-1
5 | 2014-3-01 | 2014-3-1
I want to generate the following two aggregation reports for the "arrival" column for the whole month as shown below:
(1)
arrival | count | total_monthly_arrivals
2014-03-01 | 2 | 5
2014-03-02 | 0 | 5
2014-03-03 | 0 | 5
...
2014-03-30 | 1 | 5
2014-03-31 | 1 | 5
(2)
January | 5
...
March | 5
...
December | 0 | 5
I want these 2 result sets. It generates date according & month according report and generate result set in these form.
I tried to use group by with count in first resultset but it doesn't retrieve for a date that does not exist. Again I wanna put month condition such that I choose month. where month = '02' or something like this. Is that possible?

My SQLFiddle should answer both parts of your question: http://sqlfiddle.com/#!2/9f130/31
This will return the arrival date with a count of how many people are coming that day and how many monthly arrivals there are
select distinct(r.arrival) as arrival_date,
count(r.arrival) as total_per_day,
sa.month_total as total_arrival_per_month
from reservations as r
,(select substr(arrival,6,2) as month,
count(substr(arrival,6,2)) as month_total
from reservations
group by month) as sa
where substr(r.arrival,6,2) = sa.month
group by arrival_date,total_arrival_per_month;
This will return the month of the year and how many people are booked for that month and how many are arriving that month. (Updated with the suggestion from agrizzo.)
select MONTHNAME(STR_TO_DATE(substr(r.arrival,6,2), '%m')) as arrival_date,
sa.month_total as total_arrival_per_month
from reservations as r
,(select substr(arrival,6,2) as month,
count(substr(arrival,6,2)) as month_total
from reservations
group by month) as sa
where substr(r.arrival,6,2) = sa.month
group by arrival_date,total_arrival_per_month;
There is however, no way for me to give you every day/month of the year without a fully qualified data set, provided by and prefilled by you. That's on you to do and provide us with.
However, you can check this thread. Get a list of dates between two dates and leverage their information with my queries to get your desired results.

Related

displays the data for the last 3 months available in the table MYSQL

I have the following invoice data :
tbl_invoice :
+------------+--------+
| date | no_inv |
+------------+--------+
| 2021-01-02 | INV1 |
| 2015-01-02 | INV2 |
| 2013-01-01 | INV2 |
| 2021-01-05 | INV4 |
+------------+--------+
I want to display the last 3 months of data available even though it is different for different years, because my expected result is the last 3 months of data.
My Expectation Result :
In the invoice table from this figure, only date data are available in April 2020, May 2019 and June 2015.
I want to get the data for the last 3 months. How can SQL get results according to my expectations?
Assuming your date column is a datetime type, you can do this with a simple where.
You need to calculate the date 3 months ago, and filter to where date is greater than that. e.g.:
WHERE date > DATE_SUB(NOW(), INTERVAL 3 MONTH);
See the datetime arithmetic functions here:
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html
Solved with :
SELECT date
FROM invoice
GROUP BY MONTH(date)
ORDER BY date DESC
LIMIT 3

How do I select from MySQL all rows that fall within a month but may have dates in the next month?

I have a table that looks kind of like this;
ID | netID | indate | outdate | name | org
=====================================================================
1 | 50 | 2020-03-31 23:50 | 2020-03-31 23:32 | Bill | orgA
2 | 50 | 2020-03-31 23:51 | 2020-03-31 23:32 | Fred | orgA
3 | 50 | 2020-04-01 00:02 | 2020-04-01 00:05 | Sam | orgA
4 | 51 | 2020-03-31 23:50 | 2020-03-31 23:32 | Harry | orgB
5 | 51 | 2020-03-31 23:51 | 2020-03-31 23:32 | George | orgB
6 | 51 | 2020-04-01 00:02 | 2020-04-01 00:05 | Tom | orgB
I need to write a report by org & year & month, but any row that has the same netID must be included even if it its in a different year or month. And I can't say "WHERE netID = 50" for example because I don't know what netID's are in the month '03' of the year '2020'.
I'm looking for the first three rows to be returned if I need a March 2020 report for orgA.
Below doesn't work for what I need, and I can't figure out how to get all of the rows for each netID regardless of month. Can someone please give me an example of how to retrieve them?
SELECT date(iodate) as logdate,
Name,
netID,
COALESCE( netID, 'Month Total') AS netTTL,
COUNT(ID) AS idCount,
month(logdate AS month
FROM table
WHERE org = 'orgA'
AND year(indate) = '2020'
AND month(iodate) = '03'
GROUP BY year(logdate), month, netID WITH ROLLUP
One method to get all rows where any row exists, that has the same net ID, the requested organization and a date in the requested range is getting the net IDs for the range and organization in a derived table and then join the table.
SELECT t1.*
FROM (SELECT DISTINCT
t2.netid
FROM elbat t2
WHERE t2.org = 'orgA'
AND t2.indate >= '2020-03-01'
AND t2.indate < '2020-04-01') x
INNER JOIN elbat t1
ON t1.netid = x.netid;
A few notes:
You should use range expressions rather than applying year() and month() to the date in the WHERE clause. Range expressions can use indexes and speed up the query.
In your query you have columns/expressions that are neither applied to an aggregation function nor in the GROUP BY. Though older or badly configured MySQL servers accept that, it may produce funny results. But since you didn't further explain what you want to do there, there's not much more to say here than "You're doing it wrong!".

Using multiple group_concats and group by on the same field in MySQL

I am trying to write a query that tracks the occurrences over a one-month span, with each day of the month being a column of the result. When trying to use group_concat for each day of the month, only the date of the first occurrence is returned. I've included the schemas and data of the 2 tables that I'm working with below, as well as the result that I expect to see and the SQL query that I've tried.
Note: I've simplified the data and schema as much as possible to get to the root of the question.
Tracking
tracking_id | date
_______________________________________
1 | 2017-05-01
2 | 2017-05-02
TrackingStatus
trackingstatus_id | tracking_id | time
___________________________________________
1 | 1 | 09:00
2 | 2 | 10:00
3 | 2 | 14:00
Desired Result
Month | Day1 | Day2
5 | 09:00 | 10:00,14:00
I tried the following query
SELECT
MONTH(date),
if( date = '2017-05-01', group_concat(timeadministered), NULL ),
if( date = '2017-05-02', group_concat(timeadministered), NULL )
FROM trackingstatus ts
JOIN tracking t ON t.tracking_id = ts.tracking_id
GROUP BY MONTH(date)
But am getting the following result
Month | Day1 | Day2
5 | 09:00,10:00,14:00 |
I know that when I use the group by on the date, only the first date value is recognized by the row. Is there a better way to go about this then using group by and group_concat?
You probably want an aggregate function around the expressions in the SELECT list. But wrapping another aggregate around GROUP_CONCAT doesn't make a lot of sense, since the expression in the GROUP BY clause means you will only get back one row for each month.
Maybe you are wanting something like this:
SELECT MONTH(t.date)
, GROUP_CONCAT(IF(t.date = '2017-05-01',t.timeadministered,NULL)) AS Day01
, GROUP_CONCAT(IF(t.date = '2017-05-02',t.timeadministered,NULL)) AS Day02
FROM ...
GROUP BY MONTH(t.date)

Select dates between date range and sum over a column

I have the following tables:
Let's assume the first table represents a booking made by a customer for a hotel.
+------------+-----------+-----------+--------------+----------------+
| booking_id | client_id | room_type | arrival_date | departure_date |
+------------+-----------+-----------+--------------+----------------+
| 1 | 1 | 1 | 2016-05-30 | 2016-06-03 |
+------------+-----------+-----------+--------------+----------------+
The second table contains the prices for different types of room. The prices vary for different periods of time.
+---------------+-----------+------------+------------+-------+
| room_price_id | room_type | start_date | end_date | price |
+---------------+-----------+------------+------------+-------+
| 1 | 1 | 2016-03-01 | 2016-05-31 | 150 |
| 2 | 1 | 2016-06-01 | 2016-08-31 | 200 |
+---------------+-----------+------------+------------+-------+
My question is: how can I calculate the total cost for a booking if the price is not the same during the whole period of the booking? (in my case the total cost would be 700)
I read the following links: MySQL: Select all dates between date range and get table data matching dates and Select data from date range between two dates, but I don't get it on how to solve my problem since the entries in the table with the prices contain only date ranges and not explicit dates as in the first link.
The trick with your question is in formulating the join condition between the booking and prices tables. Once this is out of the way, a simple aggregation gets you the result you want. The join condition should be true whenever any point in a given price range falls within the range of the arrival or departure date.
Then, to count days we use the greater of the arrival date or the start date, and the lesser of the departure date or the end date.
SELECT
b.booking_id,
SUM((DATEDIFF(LEAST(b.departure_date, p.end_date),
GREATEST(b.arrival_date, p.start_date)) + 1) * p.price) AS total
FROM booking b
INNER JOIN prices p
ON b.room_type = p.room_type AND
(p.start_date BETWEEN b.arrival_date AND b.departure_date OR
p.end_date BETWEEN b.arrival_date AND b.departure_date)
GROUP BY b.booking_id;
The output for your sample data is 900. This is correct because:
2 days x 150 = 300
3 days x 200 = 600
total = 900
Demo here:
SQLFiddle
And here is another demo which highlights the case where a stay overlaps an entire price range.

Order By a month name

I am storing data in my database. The data being stored looks like this
id | upload_month | created_at
-----------------------------------------
1 | Febuary | 2017-01-30 13:22:39
-----------------------------------------
2 | January | 2017-01-30 13:23:42
-----------------------------------------
3 | January | 2017-01-30 13:25:33
What I needed to do was get the unique upload_months, always using the latest created_at date. So for the above I was after something like this
id | upload_month | created_at
-----------------------------------------
1 | Febuary | 2017-01-30 13:22:39
-----------------------------------------
2 | January | 2017-01-30 13:25:33
-----------------------------------------
To achieve this I have the following SQL
SELECT *
FROM uploaded_file
JOIN (SELECT uploaded_file.upload_month, MAX(uploaded_file.created_at) created_at
FROM uploaded_file
GROUP BY uploaded_file.upload_month) months
ON uploaded_file.upload_month = months.upload_month
AND uploaded_file.created_at = months.created_at
Now the above works well, but now I am looking to order the result of the above by the upload_month. So ideally, the above should have January first and then Febuary.
Is there any way I can order by the upload_month?
Thanks
Assuming all you care about is getting the months in chronological order without regard to the year, then you can format the month as a date, and then sort by that.
For example:
order by str_to_date(concat(year(current_date()),'-', upload_month,'-01'),'%Y-%M-%d')
you can convert month name into number and use it as order by like this.
order by month(str_to_date(upload_month,'%M'))
ORDER BY CASE months.upload_month
WHEN 'January' THEN 1
WHEN 'February' THEN 2
-- ... You get the idea
WHEN 'December' THEN 12
END
And next time you can store month as TINYINT to avoid this problem.