Datediff in MsAccess - ms-access

I am stuck in one place.
I am using DateDiff in Ms Access it is giving me proper output, like
StartDate is 10-Sep-2016
EndDate is 15-Oct-2016
Total Days which I will get is 35
& months will i get is 1 Month
DateDiff('d',StartDate,EndDate)
**But I want output as 2 months if it is exeeded the 30 days.
if it is 61 days then 3 months & so on.
**IIFFF days diffrence is
29 Days then output should be 1 months
30 Days then output should be 1 months
32 Days then output should be 2 months
60 Days then output should be 2 months
62 Days then output should be 3 months**
Will that be possible in the DateDiff in MsAccess
or is there any other function available so that i can achieve the same output.**

You can do this using conditional logic. Perhaps something like this:
select iif(DateDiff('d', StartDate, EndDate) > 30,
DateDiff('d',StartDate,EndDate) & " days",
"2 months"
)
Your logic that anything exceeding 30 days is "2 months" seems strange. Normally, I think the logic would look like this:
select iif(DateDiff('d', StartDate, EndDate) > 30,
DateDiff('d', StartDate, EndDate) & " days",
DateDiff('m', StartDate, EndDate) & " months"
)

will this logic suffice to modify your SQL function?
Public Function FN_GET_MONTH(iDays As Long, Optional iDaysInMonth As Long = 30)
If (iDays / iDaysInMonth) > iDays \ iDaysInMonth Then
FN_GET_MONTH = (iDays \ iDaysInMonth) + 1
Else
FN_GET_MONTH = (iDays \ iDaysInMonth)
End If
End Function
?FN_GET_MONTH(29) = 1
?FN_GET_MONTH(31) = 2
?FN_GET_MONTH(60) = 2
?FN_GET_MONTH(80) = 3
?FN_GET_MONTH(91) = 4
you can have this public function and use it in your SQL code like
FN_GET_MONTH(DateDiff("d", StartDate, EndDate))

This query seems to give the results you seek:
SELECT
StartDate,
EndDate
numDays,
((numDays - 1) \ 30) + 1 AS numMonths
FROM
(
SELECT
StartDate,
EndDate,
DateDiff("d", StartDate, EndDate) AS numDays
FROM YourTable
)
It gives me
numDays numMonths
------- ---------
...
29 1
30 1
31 2
32 2
...
59 2
60 2
61 3
62 3
...

It seems like your minimum count of months for a positive count of days is 1, thus:
MonthCount = Sgn(DateDiff("d",StartDate,EndDate)) + DateDiff("m",StartDate,EndDate)
Edit
For a 30-day cut that will produce your example output, use this simple formula in your query:
MonthCount: (DateDiff("d",[StartDate],[EndDate])-1)\30+1

Related

from and to ranges in mysql

Currently I have this kind of query
SELECT
part_number,
part_name,
attenuation_low_end,
attenuation_high_end,
optimum_fermentation_temp_f_low,
optimum_fermentation_temp_f_high
FROM
yeast_module
WHERE
category = 3
AND
(
( `attenuation_low_end` > '31' OR `attenuation_low_end` = '31' )
AND
( `attenuation_high_end` < '40' OR `attenuation_high_end` = '40' )
)
Where I'm trying to get the records with the range of low to high end from 31 and maximum of 40
But it returns me something like this
As you can notice it seems doesn't return the data between 31 to 40
Am I doing this right?
UPDATE
I'm expecting no return since, there's no data between 31-40
You're comparing strings, which performs lexicographic comparisons rather than numeric comparisons. You need to convert to numbers. Adding 0 to a numeric string is a simple way to convert it to a number.
WHERE 0+attenuation_low_end >= 31 AND 0+attenuation_high_end <= 40
If you want ranges contained in the 31-40 range:
where attenuation_low_end >= 31 and attenuation_high_end <= 40
If you want ranges that overlap the 31-40 range:
where attenuation_low_end <= 40 and attenuation_high_end >= 31
If your data is of a string datatype, then you need to convert the values to integers so they can be compared as such.
Containment:
where attenuation_low_end + 0 >= 31 and attenuation_high_end + 0 <= 40
Overlap:
where attenuation_low_end + 0 <= 40 and attenuation_high_end + 0 >= 31

Checking to see if today is in the scheduled day utilizing a binary mapping table in SQL

I am pulling XML data from a 3rd party application using SQL Server 2008 (which I only have read-only access to the DB) and it stores the day or days of the week a job is supposed to run in one of those XML fields.
SQL uses a recursive day code of Sunday=1, Monday=2, Tuesday=4, Wednesday=8, Thursday=16, Friday=32, Saturday=64.
I am pulling the day from this XML field like the following.
case
when (job.SJDefn.value('(schedules/schedule/name)[1]', 'varchar(30)') ) like '%Week%'
then job.SJDefn.value('(/schedules/schedule/recurring/date/week/day_of_week)[1]', 'int')
else 0
end as JDOW,
I was originally utilizing the this to determine the current date of the week as but the values were obviously not compatible.
DATEPART(dw, getdate()) AS CDOW, -- Sun 1 Mon 2 Tue 3 Wed 4 Thu 5 Fri 6 Sat 7`
So I moved to:
case DATEPART(dw, getdate())
when 1 then 1 -- Sunday (1=1)
when 2 then 2 -- Monday (2=2)
when 3 then 4 -- Tueday (3=4
when 4 then 8 -- Wednesday (4=8)
when 5 then 16 -- Thursday (5=16)
when 6 then 32 -- Friday (6=32)
when 7 then 64 -- Saturday (7=64)
else NULL
end as CDOW,
The challenge is that it is an easy translation when the job just runs one day of a week.. but what about Monday/Wednesday/Friday well that is 42 which is an aggregate of the days Monday (2) + Wednesdays (8) + Friday (32).
I could translate this to text like in this question and do a string compare to a temp table but that seems inefficient.
I know that there is a table that can be built like this code to build a comparison table and I've checked the SQL Server Agent documentation (which this isn't but it is quite similar.
It seems like all possible combinations for Sunday - Saturday are basically a bitmap ranged from 1-127.. such as 42 = 0010 1010 which could be an on/off values for each day (first position always 0, 127 = 0111 111) and with that.
Position 1 = Always 0 ; binary 0000 0000
Position 2 = Sunday 1 ; binary 0000 0001
Position 3 = Monday 2 ; binary 0000 0010
Position 4 = Tueday 4 ; binary 0000 0100
Position 5 = Wednesday 8 ; binary 0000 1000
Position 6 = Thursday 16 ; binary 0001 0000
Position 7 = Friday 32 ; binary 0010 0000
Position 8 = Saturday 64 ; binary 0100 0000
I am thinking about how to potentially use a bitwise & operator but it compares the entire bit for an exact match and not a single position as I understand it so not thinking it will accomplish exactly what I want.
What I want is if the current day is in the schedule I get a true / false result from the comparison. I don’t care about interpreting the values into plain English.. For example if the string was 0011 1110 (Monday - Friday), then if the current day value is the equivalent of 0000 0010 (Monday) I be get true. If it was Sunday (0000 0001) it would be false if the reference was that 0010 1110.
I would really think there is a much simpler way of simply checking if the current day falls into the configuration in a few lines vs. building a temporary table to compare against.
So my question: given the information above, is there a simple function / query that I can execute to compare the two and return a boolean result (0/1 or Y/N) if the the current day matches the schedule?
This will give you a 1/0 result for the current date given a schedule bitmap:
declare #Today as Date = GetDate();
-- Assuming that ##DateFirst is correctly set:
declare #DoW as Int = DatePart( weekday, #Today );
-- Shift a bit to the appropriate position.
declare #Mask as Int = Power( 2, #DoW - 1 );
-- Sample schedule bitmap.
declare #Schedule as Int = 42;
-- Sign is used to convert the result of the bitwise-and to a 0 or 1.
-- Any positive value, indicating the corresponding bit is set, will return 1.
-- If there is no match, the result will be zero.
select #Today as Today, #DoW as Dow, #Mask as Mask, #Schedule as Schedule,
Sign( #Schedule & #Mask ) as IsScheduledToday;
As a professor once said, "you're always off by one in this business." It may need a tweak, but should be close.
It's a little difficult to tell exactly what you're trying to do here. You've explained the problem, but didn't provide any desired output. Since you have read-only access, however, I assume you're only interested in querying the data.
However, if you have an integer like 42, and you want to test bitwise if the bit for Monday is set (that is, 2's place), then you do this:
42 & 2 = 2
If you want to display days of the week you could do something like:
SELECT
CASE WHEN JDOW & 1 = 1 THEN 'U' ELSE '' END
+ CASE WHEN JDOW & 2 = 2 THEN 'M' ELSE '' END
+ CASE WHEN JDOW & 4 = 4 THEN 'T' ELSE '' END
+ CASE WHEN JDOW & 8 = 8 THEN 'W' ELSE '' END
+ CASE WHEN JDOW & 16 = 16 THEN 'R' ELSE '' END
+ CASE WHEN JDOW & 32 = 32 THEN 'F' ELSE '' END
+ CASE WHEN JDOW & 64 = 64 THEN 'S' ELSE '' END AS scheduled_days
FROM (VALUES (42),(84),(96), (4)) UnnamedTable (JDOW)
If you want you could create another table:
CREATE TABLE BitwiseWeekDay (
code tinyint primary key not null,
day_name nvarchar(10) not null,
day_short_name nvarchar(4) not null,
day_code nvarchar(1) not null
)
INSERT INTO BitwiseWeekDay VALUES
(1,'Sunday','Sun','U'),
(2,'Monday','Mon','M'),
(4,'Tuesday','Tue','T'),
(8,'Wednesday','Wed','W'),
(16,'Thurday','Thur','R'),
(32,'Friday','Fri','F'),
(64,'Saturday','Sat','U')
SELECT u.JDOW,
b.code,
b.day_name
FROM (VALUES (42),(84),(96), (4)) u (JDOW)
INNER JOIN BitwiseWeekDay b
ON u.JDOW & b.code = b.code
ORDER BY u.JDOW, b.code
But, I don't really know what you're looking for.

SSRS Expression First Day of of First Week of Current Year

Everyone,
I have a question that has stumped me for a day and can't figure out. What I am looking for is a formula in SSRS Expression that will tell me what the date is for the first day of the first ISO week of the current year.
For Example:
2014 would yield: 12/30/2013. The reason for this would be that the first ISO week of the 2014 year is from (12/30/2013) - (01/05/2014).
2013 would yield: 12/31/2012
I would appreciate any help anyone?
Thanks,
You can use this function:
Public Function dtFirstDayOfISOYear(ByVal intYear As Integer) as Datetime
'the first week of a ISO year is the week that contains the first Thursday of the year (and, hence, 4 January)
Dim intDayOfWeek As Integer = CInt(New DateTime(intYear, 1, 4).DayOfWeek)
'ISO weeks start with Monday
If intDayOfWeek < DayOfWeek.Monday Then intDayOfWeek = intDayOfWeek + 7
Return DateAdd(DateInterval.Day, -intDayOfWeek + 1, New DateTime(intYear, 1, 4))
End Function
And call it using an Expression like this:
=Code.dtFirstDayOfISOYear(2014)
You can also use a standalone Expression like this:
=DateAdd("d", (-1) * (CInt(New DateTime(2014, 1, 4).DayOfWeek) + IIf(CInt(New DateTime(2014, 1, 4).DayOfWeek) < DayOfWeek.Monday, 7, 0)) + 1, New DateTime(2014, 1, 4))

Determining time ranges within pre-defined shifts in MySQL

I'm working with a timecard database and trying to determine how much time for each punch falls into each one of three distinct shift periods.
For example
shift 1 = 7AM - 3pm
shift 2 = 3pm - 11pm
shift 3 = 11pm - 7am
Joe clocks in at 6:45AM and out at 1:45PM
15 minutes of this would need to be calculated as time on shift 3, but I'm not sure how to go about slicing out that bit of time in MySQL. All I have are a time in and time out field.
There are three shift periods:
Shift TimeStart TimeEnd
1 07:00 15:00
2 15:00 23:00
3 23:00 07:00
Sample Data
ID TimeIn TimeOut Hours
100 2014-07-31 06:45 2014-07-31 13:45 7
Desired Result
ID Shift TimeWorked
100 1 06:45
100 2 00:00
100 3 00:15
SQL Fiddle
I was able to come up with a solution for this using PHP.
What I did was loop through each punch, minute by minute, and determine what shift each one minute time span applies to. Within the loop, I increment one of 4 variable for shifts 1, 2, 3 or 0(no shift pay), and at the end, dump those variables to the database for the record being analyzed.
$query = "SELECT * FROM source_filtered_timecard";
$result_set = mysqli_query($connection, $query);
while($record = mysqli_fetch_assoc($result_set)) {
$checkCount++;
$shift1_hours = 0; $shift2_hours = 0;
$shift3_hours = 0; $shift0_hours = 0;
$time = strtotime($record['in_time']);
$time_out = strtotime('-1 Minute',strtotime($record['out_time']));
while($time <= $time_out) {
$mysql_time = date('G:i:s',$time);
//SELECT SHIFT CODE THAT APPLIES TO CURRENT PIT//
$query = "SELECT shift FROM shift_rules WHERE STR_TO_DATE('{$mysql_time}','%H:%i:%S') BETWEEN start_time_24 AND end_time_24 LIMIT 1";
$current_shift_set = mysqli_query($connection, $query);
if(mysqli_num_rows($current_shift_set) == 1) {
$current_shift = mysqli_fetch_assoc($current_shift_set);
if($current_shift['shift'] == '1'){$shift1_hours++;}
elseif($current_shift['shift'] == '2'){$shift2_hours++;}
elseif($current_shift['shift'] == '3'){$shift3_hours++;}
else{$shift0_hours++;}
} else {
$shift0_hours++;
}
//INCRIMENT TIME BY 1 MINUTE//
$time = strtotime("+1 minute",$time);
}
$shift1_hours = $shift1_hours/60;
$shift2_hours = $shift2_hours/60;
$shift3_hours = $shift3_hours/60;
$shift0_hours = $shift0_hours/60;
//UPDATE TIMECARD ROWS WITH SHIFT HOURS//
$query = "UPDATE source_filtered_timecard
SET shift1_time = {$shift1_hours},
shift2_time = {$shift2_hours},
shift3_time = {$shift3_hours},
shift0_time = {$shift0_hours}
WHERE id = '{$record['id']}'";
$update = mysqli_query($connection, $query);
}
I'd do this in PHP. Looking at Joe's example, it is initially tempting to try to work out how his data maps onto the shift rules. However, I think it would be a neater solution to do it the other way around i.e. map the rules onto his data, until there is no data to classify.
The algorithm might go a bit like this:
Joe's remaining time is 6:45 - 13:45
Let's map the first rule onto it (i.e. how much of this rule contributes to that range?):
shift 1 = 7:00 - 15:00 (6:45 hours)
Now Joe's remaining time is:
6:45 - 7:00
Do the next rule:
shift 2 = 15:00 - 23:00 (0 hours)
Joe's remaining time is therefore unchanged. And finally the last rule:
shift 3 = 23:00 - 1d7:00 (0:15 hours)
There are a few things to note:
The amount of worked time could be stored in an array (a "worked time set"). It starts off as a simple start and end, but if a rule removes a chunk of time from the middle, it may split into two starts and two ends
When applying a rule, convert them to actual timestamps (i.e. a date and a time) so the wrapping to the next day works correctly
Write a function that takes a worked time set, plus a rule start and end timestamp, modifies a worked time set, and returns a number of hours for the rule
First you need to add day column for differentiate time from 23:59:59 to next day time.
id| shift_name | time_start | time_end | day
1 | Day Shift | '07:00:00' | '18:59:59' | 1
2 | Night Shift | '19:00:00' | '06:59:59' | 2
Procedure :
DELIMITER $$ CREATE PROCEDURE sp_check_shift(IN intime time) PROC: begin IF(intime>='00:00:01' AND intime<='23:59:59') THEN IF ( SELECT 1 FROM tbl_shift WHERE time_start<=intime AND time_end>=intime AND day=1) THEN SELECT shift_name FROM tbl_shift WHERE time_start<=intime AND time_end>=intime AND day=1;ELSEIF ( SELECT 1 FROM tbl_shift WHERE time_start<=intime AND day=2) THEN SELECT shift_name FROM tbl_shift WHERE time_start<=intime AND day=2;ELSEIF ( SELECT 1 FROM tbl_shift WHERE time_end>=intime AND day=2) THEN SELECT shift_name FROM tbl_shift WHERE time_end>=intime AND day=2;END IF;ELSE SELECT 'Invalid Time' shift_name;END IF;END$$ delimiter ;

Convert and round (Seconds to Minutes) with SQL

I have a field on my table which represents seconds, I want to convert to minutes
Select (100/60) as Minute from MyTable
-> 1.66
How can I get 1 minute and 40 seconds 00:01:40 and then round to 00:02:00 and if 00:01:23 round to 00:01:30
Using Mysql.
There are two ways of rounding, using integer arithmetic and avoiding floating points, a value to the nearest thirty seconds...
((seconds + 15) DIV 30) * 30
(seconds + 15) - (seconds + 15) % 30
The latter is longer, but in terms of cpu time should be faster.
You can then use SEC_TO_TIME(seconds) to get the format hh:mm:ss, and take the right 5 characters if you really need hh:mm.
If you wanted to avoid SEC_TO_TIME(seconds), you can build up the string yourself.
minutes = total_seconds DIV 60
seconds = total_seconds % 60
final string = LPAD(minutes, 2, '0') | ':' | LPAD(seconds, 2, '0')
i am not sure about how to round it but you can convert seconds into time i.e hh:mm:ss format using SEC_TO_TIME(totaltime)
Desired result :
A = 30
B = 60
C = 90
D = 120
select
(25 + 15)-(25 + 15) % 30 as A,
(32 + 15)-(32 + 15) % 30 as B,
(90 + 15)-(90 + 15) % 30 as C,
(100 + 15)-(100 + 15) % 30 as D
Result :
A = 30
B = 30
C = 90
D = 90
I try with this:
select
30* ceil(30/30) as A,
30* ceil(32/30) as B,
30* ceil(90/30) as C,
30* ceil(100/30) as D
Result :
A = 30
B = 60
C = 90
D = 120
Thank you for your help !
You can simply write your own function http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html
But I'd rather do that in a programing language (PHP, Python, C), not on the database side.