I have three tables, One of which is a master calendar that houses an indicator for company Holidays. I would like to exlude Holiday from my DateDiff calculation. Below is what I have...
alert date 12/23/16
complete date 12/28/16
company Holiday 12/26/16 Need to exlude from DateDIff calculation
--My calculation shows 3 business days it should exclude 12/26/16 = 2 business days
DATEDIFF(DD,A.ALERTS_CREATE_DT,S.CreatedDate)
-(DATEDIFF(WK,A.ALERTS_CREATE_DT,S.CreatedDate) * 2) --HOW MANY WEEKEND DAYS PASSED BY
-(CASE WHEN DATENAME(DW,A.ALERTS_CREATE_DT) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(DW,S.CreatedDate) = 'Saturday' THEN 1 ELSE 0 END)
-(CASE WHEN CAL.GRH_HOLIDAY_IND = 'Y' THEN 1 ELSE 0 END)
-( SELECT COUNT(CAL.GRH_HOLIDAY_IND)
FROM A
FULL OUTER JOIN S ON A.ID= S.ID
INNER JOIN CAL ON A.ALERTCREATEDT_MMDDYYYY = CAL.CALENDAR_DATE
WHERE 1=1
AND Cal.GRH_HOLIDAY_IND = 'Y'
AND CAL.CALENDAR_DATE between CAST(A.CREATE_DT AS DATE) AND CAST(S.CreatedDate AS DATE) ) AS BusinessDays
Trying to remove the Holidays is where I'm struggling, see below.
-( SELECT COUNT(CAL.GRH_HOLIDAY_IND)
FROM A
FULL OUTER JOIN S ON A.ID= S.ID
INNER JOIN CAL ON A.ALERTCREATEDT_MMDDYYYY = CAL.CALENDAR_DATE
WHERE 1=1
AND Cal.GRH_HOLIDAY_IND = 'Y'
AND CAL.CALENDAR_DATE between CAST(A.CREATE_DT AS DATE) AND CAST(S.CreatedDate AS DATE
After 2 case statements you can add below statement to subtract no of days from holiday Calendar table.
- (select ISNULL(count(1),0) from Cal where Cal.Holiday between ALERTS_CREATE_DT AND CreatedDate )
Related
I have a table "vacancies", which consists of an id, vacancy_status_id, published_date, created and updated.
The created indicates the time the row was created in the database, the updated indicates last time any value in the row changed and published_date indicates the time the vacancy went to status 2 (active).
Apart from that I have created a calendar table that contains all dates from 2010-01-01 to 2050-12-31 (as described here: https://ubiq.co/database-blog/fill-missing-dates-in-mysql/ )
I want to get the amount of active vacancies and the amount of inactive vacancies per day starting from the date the first vacancy was created in my database.
The tricky part is, that the active vacancies are calculated based on the "published_date" field, while the inactive vacancies are based on the "updated" field.
I am able to write this query as 2 separate queries, but I'm not able to combine these into one query:
SELECT c.datefield AS created,
SUM(case when v.vacancy_status_id=2 then 1 else 0 end) as amount_active_vacancies
FROM calendar AS c
LEFT OUTER JOIN vacancy AS v ON c.datefield = DATE(v.published_date)
WHERE c.datefield BETWEEN (SELECT MIN(DATE(created)) FROM vacancy) AND DATE(NOW() - INTERVAL 1 DAY)
GROUP BY c.datefield
SELECT c.datefield AS created,
SUM(case when v.vacancy_status_id=3 OR v.vacancy_status_id=4 then 1 else 0 end) as amount_inactive_vacancies
FROM calendar AS c
LEFT OUTER JOIN vacancy AS v ON c.datefield = DATE(v.updated)
WHERE c.datefield BETWEEN (SELECT MIN(DATE(created)) FROM vacancy) AND DATE(NOW() - INTERVAL 1 DAY)
GROUP BY c.datefield
How could I combine these two in one query ?
My result should show :
created | amount_active_vacancies | amount_inactive_vacancies
If your two queries are correct, you can join them together
SELECT a.created, a.amount_active_vacancies, b.amount_inactive_vacancies
FROM (
SELECT c.datefield AS created,
SUM(case when v.vacancy_status_id=2 then 1 else 0 end) as amount_active_vacancies
FROM calendar AS c
LEFT OUTER JOIN vacancy AS v ON c.datefield = DATE(v.published_date)
WHERE c.datefield BETWEEN (SELECT MIN(DATE(created)) FROM vacancy) AND DATE(NOW() - INTERVAL 1 DAY)
GROUP BY c.datefield
) a
JOIN (
SELECT c.datefield AS created,
SUM(case when v.vacancy_status_id=3 OR v.vacancy_status_id=4 then 1 else 0 end) as amount_inactive_vacancies
FROM calendar AS c
LEFT OUTER JOIN vacancy AS v ON c.datefield = DATE(v.updated)
WHERE c.datefield BETWEEN (SELECT MIN(DATE(created)) FROM vacancy) AND DATE(NOW() - INTERVAL 1 DAY)
GROUP BY c.datefield
) b
WHERE a.created = b.created
or combine the conditions
SELECT c.datefield AS created,
SUM(case when v.vacancy_status_id=2 then 1 else 0 end) as amount_active_vacancies,
SUM(case when v.vacancy_status_id=3 OR v.vacancy_status_id=4 then 1 else 0 end) as amount_inactive_vacancies
FROM calendar AS c
LEFT OUTER JOIN vacancy AS v ON c.datefield = DATE(v.published_date) OR c.datefield = DATE(v.updated)
WHERE c.datefield BETWEEN (SELECT MIN(DATE(created)) FROM vacancy) AND DATE(NOW() - INTERVAL 1 DAY)
GROUP BY c.datefield
I'm trying to create a Sql query where I can sums for 4 different date range.
SELECT t.TenantID, t.TenantFName, t.TenantLName, u.UnitName,
TotalDebit, HousingDebit, TotalCredit, HousingCredit
FROM Tenants t
JOIN Units u ON t.UnitID = u.UnitID
LEFT JOIN (
Select
TenantID,
SUM(CASE WHEN TransactionTypeID = 1 AND ChargeTypeID != 6 THEN TransactionAmount ELSE 0 END) AS TotalDebit,
From TenantTransactions
Where TenantTransactionDate BETWEEN /* Here is my issue */
Group By TenantID
) sums ON sums.TenantID = t.TenantID
Where t.Prospect = 2
AND t.PropertyID = 10
I am trying to return 4 sums:
For the last 30 days
For last 30-60 days
For last 60-90 days
Greater than 90 days ago
Does it make sense?
Thanks
You're looking for totals based on the age of the transaction. We can get that by subtracting the transaction date from today to get a result in days:
datediff(now(), TenantTransactionDate)
You want to group that into period by 30 days, so we use integer division to get a period:
datediff(now(), TenantTransactionDate) DIV 30
And lastly, you want everything over 90 days grouped together:
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3)
This last expression returns a value of 0, 1, 2 or 3. We can use that to group the transactions, and total them:
SELECT TenantID,
sum(TransactionAmount) as totalDebit,
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3) as period
FROM TenantTransactions
where TransactionTypeID=1 and chargeTypeID != 6
group by tenantID, period
order by tenantID, period
Now you should be able to plug that back into your original query, and sort them:
SELECT t.TenantID, t.TenantFName, t.TenantLName, u.UnitName,
TotalDebit, HousingDebit, TotalCredit, HousingCredit
FROM Tenants t
JOIN Units u ON t.UnitID = u.UnitID
LEFT JOIN (
SELECT TenantID,
sum(TransactionAmount) as totalDebit,
if(datediff(now(), TenantTransactionDate)<90, datediff(now(), TenantTransactionDate) DIV 30, 3) as period
FROM TenantTransactions
where TransactionTypeID=1 and chargeTypeID != 6
group by tenantID, period
) sums ON sums.TenantID = t.TenantID
Where t.Prospect = 2
AND t.PropertyID = 10
order by t.tenantID, sums.period
I'm trying to find an answer to the following query:
A customer wants a single room for three consecutive nights. Find the first available date in December 2016.
As per the question, this should be the right answer. But I don't know how to solve it.
+-----+------------+
| id | MIN(i) |
+-----+------------+
| 201 | 2016-12-11 |
+-----+------------+
The link is from question number 14 here.
This is the ER diagram of the database:
I apologize that I'm a bit rusty with this kind of query and I can't guarantee that I got all of the syntax correct, but I think that something like the following might work:
SELECT id, DATE_ADD(b.booking_date, INTERVAL (end_date + 1 DAY) as date
FROM (
SELECT r.id, STR_TO_DATE('2016-01-01', '%Y-%m-%d') as start_of_month, b.booking_date as start_date, DATE_ADD(b.booking_date, INTERVAL (nights - 1) DAY) as end_date
FROM room r
LEFT JOIN booking b ON r.id = b.room_no
ORDER BY r.id, b.booking_date
) as room_bookings
WHERE DATE_DIFF(room_bookings.start_of_month, room_bookings.start_date) >= 3
OR DATE_DIFF(room_bookings.end_date, (
SELECT b2.booking_date FROM booking b2
WHERE b2.room_no = room_bookings.id AND b2.booking_date > room_bookings.start_date
ORDER BY b2.booking_date LIMIT 1)
) >= 3
In fact, now that I type that all out, you might be able to tweak the WHERE of the main query so that you don't even need the room_bookings subselect. Hopefully this helps and isn't too far off the mark.
This seems very hard to do without a calendar table -- because an appropriate room might have no booking at all during the month. Without any booking, there is no record in the month to start with.
select r.id, dte
from rooms r cross join
(select date('2018-12-01') as dte union all
select date('2018-12-02') as dte union all
. . .
select date('2018-12-32') as dte
) d
where not exists (select 1 from bookings b where b.room_no = r.id and b.booking_date = d.dte) and
not exists (select 1 from bookings b where b.room_no = r.id and b.booking_date = d.dte + interval 1 day) and
not exists (select 1 from bookings b where b.room_no = r.id and b.booking_date = d.dte + interval 2 day)
order by d.dte
limit 1;
This assumes that booking_date is the start of the stay. You need to provide the logic for a "single room".
select distinct top 1 alll.i,alll.room_no,
case
when (select count(*) from booking where room_no = alll.room_no and booking_date between dateadd(day,1,alll.i) and dateadd(day,3,alll.i)) > 0 then 'Y'
else 'N'
end as av3
from
(select c.i,b.room_no,b.booking_date
from calendar c cross join booking b
where month(c.i) = 12 and year(c.i) = 2016 and b.room_type_requested = 'single'
) as alll
join
(
select distinct c.i, b.room_no
from calendar c join booking b
on c.i between b.booking_date and DATEADD(day,b.nights-1,b.booking_date)
where month(c.i) = 12 and year(c.i) = 2016 and b.room_type_requested = 'single'
) as booked
on alll.i = booked.i
and alll.room_no <> booked.room_no
order by 1
This works. It is a little complicated but basically first checks all the rooms that are booked and then does a comparison between rooms not booked on each day of the month till the next 3 days.
My solution is separate problem into 2 parts (in the end was 2 queries joined together). May not be the most efficient but the solution is correct.
1) Of the single rooms, look at the last check-out date, and see which one is vacant first (i.e. no more bookings for the rest of the month)
2) check in between current reservations - and see if there's a 3 day gap between them
3) join those together - grab the min
WITH subquery AS( -- existing single-bed bookings in Dec
SELECT room_no, booking_date,
DATE_ADD(booking_date, INTERVAL (nights-1) DAY) AS last_night
FROM booking
WHERE room_type_requested='single' AND
DATE_ADD(booking_date, INTERVAL (nights-1) DAY)>='2016-12-1' AND
booking_date <='2016-12-31'
ORDER BY room_no, last_night)
SELECT room_no, MIN(first_avail) AS first_avail --3) join the 2 together
FROM(
-- 1) check the last date the room is booked in December (available after)
SELECT room_no, MIN(first_avail) AS first_avail
FROM(
SELECT room_no, DATE_ADD(MAX(last_night), INTERVAL 1 DAY) AS first_avail
FROM subquery q3
GROUP BY 1
ORDER BY 2) AS t2
UNION
-- 2) check if any 3-day exist in between reservations
SELECT room_no, DATE_ADD(MIN(end2), INTERVAL 1 DAY) AS first_avail
FROM(
SELECT q1.booking_date AS beg1, q1.room_no, q1.last_night AS end1,
q2.booking_date AS beg2, q2.last_night AS end2
FROM subquery q1
JOIN subquery q2
ON q1.room_no = q2.room_no AND q2.booking_date > q1.last_night
GROUP BY 2,1
ORDER BY 2,1) AS t
WHERE beg2-end1 > 3) AS inner_t
This works conceptually as the first avaiable date should always be the end of the previous booking.
SELECT MIN(DATE_ADD(a.booking_date, INTERVAL nights DAY)) AS i
FROM booking AS a
WHERE DATE_ADD(a.booking_date, INTERVAL nights DAY)
>= '2016-12-01'
AND room_type_requested = 'single'
AND NOT EXISTS
(SELECT 1 FROM booking AS b
WHERE b.booking_date BETWEEN
DATE_ADD(a.booking_date, INTERVAL nights DAY)
AND DATE_ADD(a.booking_date, INTERVAL nights+2 DAY)
AND a.room_no = b.room_no)
Good Day,
I have a table that contains 3 columns. Date, Store, Straight_Sales. Each day a new record is created for each store with their previous day's sales.
What I am trying to do is generate a result set that has both current month to date sales for each location as well as the past year same MTD sales.
I can accomplish this by using two totally separate queries and result sets however I am trying to include these in the same query for reporting purposes.
Here are my two current queries that work just fine:
Last Year Month to Date:
SELECT SUM(summ_sales_daily.straight_sales), store_master.name
FROM
store_master
INNER JOIN summ_sales_daily ON store_master.unit = summ_sales_daily.store
WHERE YEAR(date)=YEAR(DATE_SUB(NOW(), INTERVAL 1 YEAR)) AND MONTH(date)=MONTH(NOW())
GROUP BY summ_sales_daily.store ORDER BY summ_sales_daily.store
Current Year Month to Date:
SELECT SUM(summ_sales_daily.straight_sales), store_master.name
FROM
store_master
INNER JOIN summ_sales_daily ON store_master.unit = summ_sales_daily.store
WHERE YEAR(date)=YEAR(NOW()) AND MONTH(date)=MONTH(NOW())
GROUP BY summ_sales_daily.store ORDER BY summ_sales_daily.store
I'd like these to return the current and previous years MTD in the same result along with the store name (hence the join)
Any help would be awesome!
Using MariaDB
You can either use conditional aggregation and move the different conditions into a case expression within the sum function:
SELECT
store_master.name
, SUM(CASE WHEN YEAR(date)=YEAR(DATE_SUB(NOW(), INTERVAL 1 YEAR)) THEN summ_sales_daily.straight_sales ELSE 0 END) last_year_sales
, SUM(CASE WHEN YEAR(date)=YEAR(NOW()) THEN summ_sales_daily.straight_sales ELSE 0 END) current_year_sales
FROM store_master
INNER JOIN summ_sales_daily ON store_master.unit = summ_sales_daily.store
WHERE MONTH(date)=MONTH(NOW())
GROUP BY summ_sales_daily.store
ORDER BY summ_sales_daily.store;
Or you can calculate the two different values in a couple of derived tables that you join with:
SELECT
store_master.name,
last_year.sales as previous_mtd,
current_year.sales as current_mtd
FROM store_master
LEFT JOIN (
SELECT store, SUM(straight_sales) sales
FROM summ_sales_daily
WHERE YEAR(date)=YEAR(DATE_SUB(NOW(), INTERVAL 1 YEAR)) AND MONTH(date)=MONTH(NOW())
GROUP BY store
) last_year ON store_master.unit = last_year.store
LEFT JOIN (
SELECT store, SUM(summ_sales_daily.straight_sales) sales
FROM summ_sales_daily
WHERE YEAR(date)=YEAR(NOW()) AND MONTH(date)=MONTH(NOW())
GROUP BY store
) current_year ON store_master.unit = current_year.store ;
Sample SQL Fiddle
The first solution would probably perform better.
I have an existing query which gets me the parent record plus the greatest date from any child records. The child records are calls made. I have now been asked to show the date of the most recent "past" call and the date of any future "scheduled" calls.
Here is the query I am using now:
SELECT doctor.*, contact.date_scheduled
FROM doctor
LEFT JOIN contact ON doctor.doctorID = contact.doctorID
AND date_scheduled = (SELECT MAX(date_scheduled) FROM contact WHERE doctor.doctorID = contact.doctorID)
ORDER BY date_scheduled DESC
Can someone please show me how to modify this query to get the two dates as I have described above?
I think this is what you want:
SELECT d.*,
max(case when c.date_scheduled < now() then c.date_scheduled end) as MostRecentCall,
group_concat(case when c.date_scheduled >= now() then c.date_scheduled end) as FutureCalls
FROM doctor d left join
contact c
on d.doctorID = c.doctorID
GROUP BY d.doctorId;
This will put future call dates in a list, separated by commas.
EDIT:
If you only want doctors that have calls scheduled in the future, then use a having clause:
SELECT d.*,
max(case when c.date_scheduled < now() then c.date_scheduled end) as MostRecentCall,
group_concat(case when c.date_scheduled >= now() then c.date_scheduled end) as FutureCalls
FROM doctor d left join
contact c
on d.doctorID = c.doctorID
GROUP BY d.doctorId
HAVING sum(c.date_scheduled >= now()) > 0;