how to assemble date and time from two different table columns - mysql

[![enter image description here][1]][1]I have a requirement to return a result of a orders where the condition is that we have a orderDate which is Date field in a table and one orderCloseTime for the same order which is in different table having only time value.
I have to compare the orderDate with now() but the time should compare from orderCLoseTime column from another table.
i.e if the orderCloseTime is having data 2017-07-17 09:40:12 which is today but if it has passed the time orderCloseTIme then that data should not return in the query.
In Below query, if i have date as a future date then also it is not returning the data, it should only compare the today date with time.
EDIT:
select *
from opsorder mbo
where date(mbo.orderDate)>=date(now())
and storeId in
(select storeid from store mbs
INNER JOIN distributioncenter mbd on
mbd.distributionCenterId = mbs.distributionCenterId
where mbd.orderCloseTime > curtime()
and date(mbo.orderDate)>=date(now())
);

From your description of the data structure it seems that this should work. I couldn't see a reason for the use of a subquery instead of a join.
select
mbo.*,
DATE(mbo.orderDate) + ' ' + mbd.orderCloseTime AS OrderCutOffTime
from mb_opsorder mbo
inner join mb_store mbs
on mbo.storeId = mbs.storeid
inner join mb_distributioncenter mbd
on mbd.distributionCenterId = mbs.distributionCenterId
where
addtime(date(mbo.orderDate), mbd.orderCloseTime) >= now()

Related

How to compare a date with array of dates in SQL query and update a field value in MySQL?

I'm working on a task where I need to find the expected date to resolve a ticket using createdAt and sla_name fields values. After that I need to compare the this expected date with the dates in holidays table.
If the expected date falls in holidays, I need to extend the sla_name field value.
This is the query am using.
SELECT t.sla_meet, t.tid, t.ticket_id, t.ticket_name,t.createdAt,t.updatedAt,t.status, dw.dropdown_name
as ticket_priority,p.project_name, dw3.dropdown_name as ticket_status,t.sla as sla_name,
isn.issue_name as issue_type,inn.incidentName as incident_type,t.ticket_accepted_date,
t.asset_id,t.ticket_closed_date,t.contact_number,
IF(NOW() <= DATE_ADD(t.createdAt,INTERVAL (t.sla)+1 DAY),'YES','NO') AS slaMeetData
from tickets t
JOIN assets ast ON t.asset_id=ast.asset_id
JOIN projects p ON p.project_id=ast.project_id
JOIN admin_dropdowns dw ON t.ticket_priority=dw.id
JOIN admin_dropdowns dw3 ON t.ticket_status=dw3.id
JOIN issues isn ON t.issue_type=isn.issue_id
JOIN incident_names inn ON t.incident_type=inn.incidentId
order by t.tid DESC
This is the resultant data of the above query.
Now I need to compare the holidays in above query. And the sample data is,
If the expected date that am getting in IF condition of above query is falls in this holidays, I need to update the sla_name value with COUNT OF HOLIDAYS(If startdata and enddate are there, need to count the days between them) + sla_name.
If expected date is falls on dates range(start and end dates of holidays), need to calculate the count of days from expected date to end date and update that count in sla_name field
Is it possible to do this functionality in SQL? I've used the above query as VIEWS.
Instead of t.sla AS sla_name, use this expression to determine whether to add the length of the overlapping holiday to the number of days:
(
t.sla +
IF(
DATE_ADD(t.createdAt,INTERVAL (t.sla)+1 DAY) BETWEEN holidays.holiday_date AND holidays.end_date,
DATEDIFF( holidays.end_date, holidays.holiday_date ), /* add holiday length number of days */
0 /* no holiday overlap so don't add any days */
)
) as sla_name
You'll also have to join on the holidays table to find the holiday (if any) which overlaps the date in question:
JOIN holidays ON ( DATE_ADD(t.createdAt,INTERVAL (t.sla)+1 DAY) BETWEEN holidays.holiday_date and holidays.end_date )

Mysql checking . record for one day against record in different date 'Same-Store Sales'

Same-Store Sales concept if where you check how store performing today against same store yesterday to show if revenue grow or decrease.
so I have table with 5+ millions of records structured like
store_id , stats_date, trans_cnt (number of transactions),
revenue, time_period(week, day , year)
is there a way to avoid using cursor, to check if store_id record exist yesterday day and today and see if revenue goes up or down?
It can be achieved join on same filter data from table or sub table .
ie
select tdate.store_id ,(tdate.revenue - ydate.revenue) as diffrence
from (select store_id ,revenue from tablename where stats_date =getdata()) tdate
join ( select store_id ,revenue from tablename where stats_date = DATEADD(day, -1,getdata()) ) as ydate
on tdate.store_id = ydate.store_id
Note:
ydate filter data for yesterday
tdate filter data for yesterday
More filter condition can be added .
Or you are looking for
select tdate.store_id ,(tdate.revenue - ydate.revenue) as diffrence
from tablename tdate
join tablename as ydate
on tdate.store_id = ydate.store_id
and tdate.stats_date =ydate.DATEADD(day, -1,stats_date)

MySQL query to select all hostels with at least X spaces between start and end dates?

I have 2 tables, one with hostels (effectively a single-room hotel with lots of beds), and the other with bookings.
Hostel table: unique ID, total_spaces
Bookings table: start_date, end_date, num_guests, hostel_ID
I need a (My)SQL query to generate a list of all hostels that have at least num_guests free spaces between start_date and end_date.
Logical breakdown of what I'm trying to achieve:
For each hostel:
Get all bookings that overlap start_date and end_date
For each day between start_date and end_date, sum the total bookings for that day (taking into account num_guests for each booking) and compare with total_spaces, ensuring that there are at least num_guests spaces free on that day (if there aren't on any day then that hostel can be discounted from the results list)
Any suggestions on a query that would do this please? (I can modify the tables if necessary)
I built an example for you here, with more comments, which you can test out:
http://sqlfiddle.com/#!9/10219/9
What's probably tricky for you is to join ranges of overlapping dates. The way I would approach this problem is with a DATES table. It's kind of like a tally table, but for dates. If you join to the DATES table, you basically break down all the booking ranges into bookings for individual dates, and then you can filter and sum them all back up to the particular date range you care about. Helpful code for populating a DATES table can be found here: Get a list of dates between two dates and that's what I used in my example.
Other than that, the query basically follows the logical steps you've already outlined.
Ok, if you are using mysql 8.0.2 and above, then you can use window functions. In such case you can use the solution bellow. This solution does not need to compute the number of quests for each day in the query interval, but only focuses on days when there is some change in the number of hostel guests. Therefore, there is no helping table with dates.
with query as
(
select * from bookings where end_date > '2017-01-02' and start_date < '2017-01-05'
)
select hostel.*, bookingsSum.intervalMax
from hostel
join
(
select tmax.id, max(tmax.intervalCount) intervalMax
from
(
select hostel.id, t.dat, sum(coalesce(sum(t.gn),0)) over (partition by t.id order by t.dat) intervalCount
from hostel
left join
(
select id, start_date dat, guest_num as gn from query
union all
select id, end_date dat, -1 * guest_num as gn from query
) t on hostel.id = t.id
group by hostel.id, t.dat
) tmax
group by tmax.id
) bookingsSum on hostel.id = bookingsSum.id and hostel.total_spaces >= bookingsSum.intervalMax + <num_of_people_you_want_accomodate>
demo
It uses a simple trick, where each start_date represents +guest_num to the overall number of quests and each 'end_date' represents -guest_num to the overall number of quests. We than do the necessary sumarizations in order to find peak number of quests (intervalMax) in the query interval.
You change '2017-01-05' in my query to '2017-01-06' (then only two hostels are in the result) and if you use '2017-01-07' then just hostel id 3 is in the result, since it does not have any bookings yet.

Generating complex sql tables

I currently have an employee logging sql table that has 3 columns
fromState: String,
toState: String,
timestamp: DateTime
fromState is either In or Out. In means employee came in and Out means employee went out. Each row can only transition from In to Out or Out to In.
I'd like to generate a temporary table in sql to keep track during a given hour (hour by hour), how many employees are there in the company. Aka, resulting table has columns HourBucket, NumEmployees.
In non-SQL code I can do this by initializing the numEmployees as 0 and go through the table row by row (sorted by timestamp) and add (employee came in) or subtract (went out) to numEmployees (bucketed by timestamp hour).
I'm clueless as how to do this in SQL. Any clues?
Use a COUNT ... GROUP BY query. Can't see what you're using toState from your description though! Also, assuming you have an employeeID field.
E.g.
SELECT fromState AS 'Status', COUNT(*) AS 'Number'
FROM StaffinBuildingTable
INNER JOIN (SELECT employeeID AS 'empID', MAX(timestamp) AS 'latest' FROM StaffinBuildingTable GROUP BY employeeID) AS LastEntry ON StaffinBuildingTable.employeeID = LastEntry.empID
GROUP BY fromState
The LastEntry subquery will produce a list of employeeIDs limited to the last timestamp for each employee.
The INNER JOIN will limit the main table to just the employeeIDs that match both sides.
The outer GROUP BY produces the count.
SELECT HOUR(SBT.timestamp) AS 'Hour', SBT.fromState AS 'Status', COUNT(*) AS 'Number'
FROM StaffinBuildingTable AS SBT
INNER JOIN (
SELECT SBIJ.employeeID AS 'empID', MAX(timestamp) AS 'latest'
FROM StaffinBuildingTable AS SBIJ
WHERE DATE(SBIJ.timestamp) = CURDATE()
GROUP BY SBIJ.employeeID) AS LastEntry ON SBT.employeeID = LastEntry.empID
GROUP BY SBT.fromState, HOUR(SBT.timestamp)
Replace CURDATE() with whatever date you are interested in.
Note this is non-optimal as it calculates the HOUR twice - once for the data and once for the group.
Again you are using the INNER JOIN to limit the number of returned row, this time to the last timestamp on a given day.
To me your description of the FromState and ToState seem the wrong way round, I'd expect to doing this based on the ToState. But assuming I'm wrong on that the following should point you in the right direction:
First, I create a "Numbers" table containing 24 rows one for each hour of the day:
create table tblHours
(Number int);
insert into tblHours values
(0),(1),(2),(3),(4),(5),(6),(7),
(8),(9),(10),(11),(12),(13),(14),(15),
(16),(17),(18),(19),(20),(21),(22),(23);
Then for each date in your employee logging table, I create a row in another new table to contain your counts:
create table tblDailyHours
(
HourBucket datetime,
NumEmployees int
);
insert into tblDailyHours (HourBucket, NumEmployees)
select distinct
date_add(date(t.timeStamp), interval h.Number HOUR) as HourBucket,
0 as NumEmployees
from
tblEmployeeLogging t
CROSS JOIN tblHours h;
Then I update this table to contain all the relevant counts:
update tblDailyHours h
join
(select
h2.HourBucket,
sum(case when el.fromState = 'In' then 1 else -1 end) as cnt
from
tblDailyHours h2
join tblEmployeeLogging el on
h2.HourBucket >= el.timeStamp
group by h2.HourBucket
) cnt ON
h.HourBucket = cnt.HourBucket
set NumEmployees = cnt.cnt;
You can now retrieve the counts with
select *
from tblDailyHours
order by HourBucket;
The counts give the number on site at each of the times displayed, if you want during the hour in question, we'd need to tweak this a little.
There is a working version of this code (using not very realistic data in the logging table) here: rextester.com/DYOR23344
Original Answer (Based on a single over all count)
If you're happy to search over all rows, and want the current "head count" you can use this:
select
sum(case when t.FromState = 'In' then 1 else -1) as Heads
from
MyTable t
But if you know that there will always be no-one there at midnight, you can add a where clause to prevent it looking at more rows than it needs to:
where
date(t.timestamp) = curdate()
Again, on the assumption that the head count reaches zero at midnight, you can generalise that method to get a headcount at any time as follows:
where
date(t.timestamp) = "CENSUS DATE" AND
t.timestamp <= "CENSUS DATETIME"
Obviously you'd need to replace my quoted strings with code which returned the date and datetime of interest. If the headcount doesn't return to zero at midnight, you can achieve the same by removing the first line of the where clause.

fetch records less than specific "date time" after calculating the difference between two DB fields

I need to fetch all records that are less/greater/equal to a given time(travel time)(hours:minutes:seconds) for a specific date OR in a specific date time duration. for this i have write a query but it is not working.My query and database structure is as below, please help.
`SELECT vt.*, vt.id AS tripid,voi.vehicle_id,voi.fuelissue_id,voi.date, voi.driver_id,
voi.driver_name,voi.time_out,voi.time_in,voi.meter_reading_out,
voi.meter_reading_in ,voi.`departure_from`,voi.location_comments,
voi.reason,voi.date_in
FROM vehicles_out_in voi
INNER JOIN vehicle_trips vt
ON voi.id=vt.voi_id
WHERE 1=1
AND TIMESTAMP(voi.date,voi.time_out)>=TIMESTAMP('2013-10-20','01:00:00')
AND TIMESTAMP(voi.date,voi.time_out)<=TIMESTAMP('2013-10-25','06:00:00')
AND (TIMESTAMP(voi.date_in,voi.time_in)-TIMESTAMP(voi.date,voi.time_out)) <= '02:00:00')
ORDER BY voi.id DESC`
DB Structure:
`tbl1 : vehicles_out_in
driver_id
driver_name
category_id
vehicle_id
date
leavefor_location
am
zo
time_out
meter_reading_out
reason
date_in
time_in
meter_reading_in
departure_from
returned_in
fuelissue_id
expected_trips
reasonfor_lesstrips
actual_trips
vehicle_status
location_comments`
`tbl2: vehicle_trips
id
voi_id
time_trip
date_trip
dumping_site
start_reading
meter_reading_site
total_weight
empty_weight
net_weight
receipt
uc_id`
How you build your TIMESTAMP up is not quite right.
Assuming that you want to fetch all records with voi.time_out between certain points in time OR those over a certain duration. Try replacing the last 4 lines of your query with this (assuming that time_out is after time_in):
AND
(
TIMESTAMP(concat(voi.date,,' ',voi.time_out))
between TIMESTAMP('2013-10-20 01:00:00')
and TIMESTAMP('2013-10-25 06:00:00')
OR
TIMESTAMPDIFF(SECOND,concat(voi.date_in,' ',voi.time_in),concat(voi.date,' ',voi.time_out)) <= 7200
)
ORDER BY voi.id DESC