I am working in HRMS. My problem is in vacation,
If an employee take vacation from 19/3/2014 to 5/4/2014 application calculates that he take 18 days in month instead of 3 days.
I store vacations in vacation table
columns :
emp_id | vac_type | from | to
Now, How can I make query to tell me that he take 13 days in March and 5 days in April?
Excellent question! I was able to find a way to do it, but I did have to use slightly different notation for the dates (see below).
DECLARE #startDate DATETIME, #endDate DATETIME, #lastDayOfStartMonth INT
SET #startDate = '3/19/2014'
SET #endDate = '4/5/2014'
SELECT #lastDayOfStartMonth =
1+DATEPART(dd, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#startDate)+1,0)))
SELECT DATENAME(month, #startDate) AS [Month],
#lastDayOfStartMonth - DATEPART(dd, #startDate) AS [DaysSpent],
DATENAME(month, #endDate) AS [Month],
DATEPART(dd, #endDate) AS [DaysSpent]
Output:
| Month | DaysSpent | Month | DaysSpent |
|-------|-----------|-------|-----------|
| March | 13 | April | 5 |
SQL Fiddle example
My work here was based on the design from Pinal Dave's post SQL SERVER – Find Last Day of Any Month – Current Previous Next
Handling dates over more than two months
DECLARE #startDate DATETIME, #endDate DATETIME, #currentDate DATETIME, #currentDay INT
DECLARE #currentMonth INT, #lastDayOfStartMonth INT
CREATE TABLE #VacationDays ([Month] VARCHAR(10), [DaysSpent] INT)
SET #startDate = '1/19/2014'
SET #endDate = '4/5/2014'
SET #currentMonth = DATEPART(mm, #startDate)
SET #currentDay = DATEPART(dd, #startDate)
SET #currentDate = #startDate
WHILE #currentMonth < DATEPART(mm, #endDate)
BEGIN
SELECT #lastDayOfStartMonth =
DATEPART(dd, DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#currentDate)+1,0)))
PRINT #lastDayOfStartMonth
INSERT INTO #VacationDays
SELECT DATENAME(month, #currentDate) AS [Month],
#lastDayOfStartMonth - #currentDay + 1 AS [DaysSpent]
SET #currentDate = DATEADD(mm, 1, #currentDate)
SET #currentMonth = #currentMonth + 1
SET #currentDay = 1
END
IF DATEPART(mm, #startDate) = DATEPART(mm, #endDate)
BEGIN
INSERT INTO #VacationDays
SELECT DATENAME(month, #endDate) AS [Month],
DATEPART(dd, #endDate) - DATEPART(dd, #startDate) + 1 AS [DaysSpent]
END
ELSE
BEGIN
INSERT INTO #VacationDays
SELECT DATENAME(month, #endDate) AS [Month],
DATEPART(dd, #endDate) AS [DaysSpent]
END
SELECT * FROM #VacationDays
DROP TABLE #VacationDays
Output:
| Month | DaysSpent |
|----------|-----------|
| January | 13 |
| February | 28 |
| March | 31 |
| April | 5 |
SQL Fiddle example - It takes about a minute to run. It's much faster running in a local instance of SSMS.
Here's how it works
For the example below I am using a #startDate value of 05-05-2015.
The value of CAST(0 AS DATETIME) is the date 1900-01-01, so that means the line DATEDIFF(m,0,#startDate) is essentially asking, how many months have passed since January 1, 1900? For this example, that value is 1384.
DATEADD(mm, DATEDIFF(m,0,#startDate)+1,0) or DATEADD(mm, 1384+1,0) is saying, Add 1385 months to the date value 0 (or 1900-01-01). This will give us the DATETIME value of the first of the month after #startDate's month. For our example, 2015-06-01.
DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#startDate)+1,0)) or DATEADD(s,-1,'2015-06-01') subtracts 1 second from the first of next month, give us the last second of the current month, or 2015-05-31 23:59:59.
Then we use DATEPART to get the day value of that date: 31.
31 is the last day in May.
I don't know how to do this directly in SQL using a SQL query. But if you have the start and end dates of the vacation in your C# code, then you could calculate the number of days of vacation occurring in each month by doing something like the following. This got a little more complicated than I had intended, but it's the best I could come up with. For your example, this code produces the following output:
Vacation days in March: 13 days
Vacation days in April: 5 days
Code:
class Program
{
class DateRange
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
static void Main(string[] args)
{
DateRange vacation = new DateRange();
vacation.Start = new DateTime(2014, 3, 19);
vacation.End = new DateTime(2014, 4, 5);
// Assuming April 5 represents the last day of vacation, let's
// add one to it, to show that his vacation actually ends on the
// following day.
vacation.End = vacation.End.AddDays(1);
DateRange currentMonth = new DateRange();
currentMonth.Start = new DateTime(vacation.Start.Year, vacation.Start.Month, 1);
currentMonth.End = currentMonth.Start.AddMonths(1);
while (currentMonth.Start < vacation.End)
{
Console.WriteLine("Vacation days in {0}: \t{1} days",
currentMonth.Start.ToString("MMMM"),
IntersectDates(currentMonth, vacation));
currentMonth.Start = currentMonth.Start.AddMonths(1);
currentMonth.End = currentMonth.End.AddMonths(1);
}
}
// Returns the number of days represented by the intersection of the two
// date ranges.
static int IntersectDates(DateRange dateRange1, DateRange dateRange2)
{
DateTime startOfIntersection = MaxDate(dateRange1.Start, dateRange2.Start);
DateTime endOfIntersection = MinDate(dateRange1.End, dateRange2.End);
return (startOfIntersection < endOfIntersection) ?
(int)(endOfIntersection - startOfIntersection).TotalDays :
0;
}
static DateTime MinDate(DateTime d1, DateTime d2)
{
return (d1 < d2) ? d1 : d2;
}
static DateTime MaxDate(DateTime d1, DateTime d2)
{
return (d1 > d2) ? d1 : d2;
}
}
DECLARE #FromDate date = '2014-03-19', #ToDate date = '2014-05-04'
WITH CTE AS
(
SELECT
YEAR(#FromDate) * 100 + MONTH(#FromDate) AS Month,
DATEADD(DAY, -DAY(#FromDate) + 1, #FromDate) AS FirstDateOfMonth,
DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(DAY, -DAY(#FromDate) + 1, #FromDate))) AS LastDateOfMonth
UNION ALL
SELECT
YEAR(DATEADD(MONTH, 1, FirstDateOfMonth)) * 100 + MONTH(DATEADD(MONTH, 1, FirstDateOfMonth)) AS Month,
DATEADD(MONTH, 1, FirstDateOfMonth),
DATEADD(DAY, -1, DATEADD(MONTH, 2, FirstDateOfMonth))
FROM CTE
WHERE #ToDate >= LastDateOfMonth
)
SELECT
*,
CASE
-- Same month
WHEN YEAR(#FromDate) * 100 + MONTH(#FromDate) = YEAR(#ToDate) * 100 + MONTH(#ToDate) THEN DATEDIFF(DAY, #FromDate, #ToDate) + 1
-- Get day from vacation start date to last date of month
WHEN Month = YEAR(#FromDate) * 100 + MONTH(#FromDate) THEN DATEDIFF(DAY, #FromDate, LastDateOfMonth) + 1
-- Get day from first date of month to vacation end date
WHEN Month = YEAR(#ToDate) * 100 + MONTH(#ToDate) THEN DATEDIFF(DAY, FirstDateOfMonth, #ToDate) + 1
-- Full month day
ELSE DATEDIFF(DAY, FirstDateOfMonth, LastDateOfMonth) + 1
END AS Day
FROM CTE
Result
Month FirstDateOfMonth LastDateOfMonth Day
----------- ---------------- --------------- -----------
201403 2014-03-01 2014-03-31 13
201404 2014-04-01 2014-04-30 30
201405 2014-05-01 2014-05-31 4
For applications like these, a dates table can greatly simplify queries at a reasonable cost to performance. It becomes nothing more than
SELECT emp_id, d.month, COUNT(*) as days
FROM Vacations v
INNER JOIN dates d on d.theDate BETWEEN v.Start and v.End
GROUP BY emp_id, d.month
See Create Date Dimension Table in SQL Server for an example of how to create a dates table.
This also simplifies complicated queries like the number of business days in a vacation:
SELECT emp_id, COUNT(*) as days
FROM Vacations v
INNER JOIN dates d on d.theDate BETWEEN v.Start and v.End
WHERE d.IsWeekend = 0
GROUP BY emp_id
Or grouping by pay-period or quarter:
SELECT emp_id, d.year, d.quarter, COUNT(*) as days
FROM Vacations v
INNER JOIN dates d on d.theDate BETWEEN v.Start and v.End
GROUP BY emp_id, d.year, d.quarter
I create a query that needs a calendar that I make it in WITH statement, In this calendar you can set your month names and month days -for a leap year-.
The calendar will be flexible for any year that used in vacation table -that automatically generate the correct dates for leap years-, Also support vacations starts from one year to next year.
;WITH calendar AS (
SELECT years.[Year], months.monthId, months.[monthName],
CASE ISDATE(CONVERT(varchar, years.[Year])+'-'+CONVERT(varchar,months.monthId)+'-'+CONVERT(varchar,months.monthDays))
WHEN 1 THEN months.monthDays
ELSE months.monthDays-1
END AS monthDays,
CONVERT(datetime, (CONVERT(varchar, years.[Year])+'-'+CONVERT(varchar,months.monthId)+'-1')) AS startDay,
CASE ISDATE(CONVERT(varchar, years.[Year])+'-'+CONVERT(varchar,months.monthId)+'-'+CONVERT(varchar,months.monthDays))
WHEN 1 THEN CONVERT(datetime, CONVERT(varchar, years.[Year])+'-'+CONVERT(varchar,months.monthId)+'-'+CONVERT(varchar,months.monthDays))
ELSE CONVERT(datetime, CONVERT(varchar, years.[Year])+'-'+CONVERT(varchar,months.monthId)+'-'+CONVERT(varchar,months.monthDays-1))
END AS EndDay
FROM
(SELECT DISTINCT YEAR(vi.[from]) As [Year] FROM vacation vi
UNION
SELECT DISTINCT YEAR(vi.[to]) As [Year] FROM vacation vi
) As years
CROSS JOIN
(SELECT 1 As monthId, 31 As monthDays, 'January' As [monthName] UNION ALL
SELECT 2, 29, 'February' UNION ALL
SELECT 3, 31, 'March' UNION ALL
SELECT 4, 30, 'April' UNION ALL
SELECT 5, 31, 'May' UNION ALL
SELECT 6, 30, 'June' UNION ALL
SELECT 7, 31, 'July' UNION ALL
SELECT 8, 31, 'August' UNION ALL
SELECT 9, 30, 'September' UNION ALL
SELECT 10, 31, 'October' UNION ALL
SELECT 11, 30, 'November' UNION ALL
SELECT 12, 31, 'December' ) As months
)
SELECT c.[year], c.monthId, c.[monthName],
CASE
WHEN v.emp_id IS NULL THEN 0
WHEN c.monthId = MONTH(v.[from]) THEN DATEDIFF(DAY, v.[from], c.EndDay) + 1
WHEN c.monthId = MONTH(v.[to]) THEN DATEDIFF(DAY, c.startDay, v.[to]) + 1
WHEN c.monthId BETWEEN MONTH(v.[from]) AND MONTH(v.[to]) THEN c.monthDays
END As vacationDays,
CASE
WHEN v.emp_id IS NULL THEN c.monthDays
WHEN c.monthId = MONTH(v.[from]) THEN DATEDIFF(DAY, c.startDay, v.[from])
WHEN c.monthId = MONTH(v.[to]) THEN DATEDIFF(DAY, v.[to], c.EndDay)
WHEN c.monthId BETWEEN MONTH(v.[from]) AND MONTH(v.[to]) THEN 0
END As nonvacationDays,
c.monthDays
FROM
calendar c
LEFT JOIN
vacation v ON c.monthId BETWEEN MONTH(v.[from]) AND MONTH(v.[to])
The result will be like this:
year | monthId | monthName | vacationDays | nonvacationDays | monthDays
-----+---------+-----------+--------------+-----------------+------------
2014 | 1 | January | 0 | 31 | 31
2014 | 2 | February | 0 | 28 | 28
2014 | 3 | March | 13 | 18 | 31
2014 | 4 | April | 5 | 25 | 30
2014 | 5 | May | 0 | 31 | 31
--....
I want to select a result from student table-
query -
if I pass any year like 2013 then select the students join start date and end date or he is currently there
in between these year
like if any student start date year is 2010 and end date year is 2013
and I select 2011 year then show this student record also .
Table structure is-
StudentID Age startDate EndDate
1 14 5/05/2013 7/05/2013
4 17 4/04/2012 8/10/2012
and I'm trying this-
select * from tblstudent
Where DATEPART(year, StartDate) BETWEEN #year-1 AND #year
Thanks in advance.
Not sure if I understood you, but this should do the job:
select *
from tblStudent s
where #year >= DATEPART(year, StartDate) and #year <= DATEPART(year, EndDate)
Actually, you almost there.
You just need to compare year part of your StartDate is smaller or equal to your #year and year part of your EndDate is bigger or equal to your #year.
Try like this;
select *
from tblStudent
where DATEPART(year, startDate) <= #year and DATEPART(year, EndDate) >= #year
For #year = 2013, output will be;
| STUDENTID | AGE | STARTDATE | ENDDATE |
------------------------------------------------------------------------------
| 1 | 14 | May, 05 2013 03:00:00+0000 | July, 05 2013 03:00:00+0000 |
Here SQL Fiddle Demo.
I need to produce some SQL that will show me the trend (up or down tick) in some transacitons.
Consider this table with a PlayerId and a Score
PlayerId, Score, Date
1,10,3/13
1,11,3/14
1,12,3/15
If I pull data from 3/15 I have a score of 12 with an upward trend compared to the historical data.
I did something similar in Oracle 8i about 10 years ago using some of the analytical functions like rank, however it was 10 years ago....
The results would look similar to
PlayerId, Score, Date, Trend
1,12,3/15,UP
How can I do something similar with sql azure?
This SQL:
with data as (
select * from ( values
(1,11,cast('2013/03/12' as smalldatetime)),
(1,15,cast('2013/03/13' as smalldatetime)),
(1,11,cast('2013/03/14' as smalldatetime)),
(1,12,cast('2013/03/15' as smalldatetime))
) data(PlayerId,Score,[Date])
)
select
this.*,
Prev = isnull(prev.Score,0),
tick = case when this.Score > isnull(prev.Score,0) then 'Up' else 'Down' end
from data this
left join data prev
on prev.PlayerId = this.PlayerId
and prev.[Date] = this.[Date] - 1
returns this output:
PlayerId Score Date Prev tick
----------- ----------- ----------------------- ----------- ----
1 11 2013-03-12 00:00:00 0 Up
1 15 2013-03-13 00:00:00 11 Up
1 11 2013-03-14 00:00:00 15 Down
1 12 2013-03-15 00:00:00 11 Up
I have a textfield that users input the date using a modified jquery datepicker. The textfield has the Month and Year such as 'July 2011'
I need to run a query to search for results between July 1, 2011 and July 31, 2011. My date in the database is a smalldatetime, so I need my query to look like this:
select * from members where signupdate between 'july 1 2011' and 'july 31 2011'
How can I get the user inputted date of July 2011 converted to 'July 1 2011' and 'July 31 2011'?
EDIT
I'm only getting a 0 value from InvalidCount but I know I have one record in there as a test. Why isn't it being counted?
MY PROC:
SELECT
(SELECT COUNT(*) FROM dbo.Members m WHERE m.memberID = #pMemberID AND m.SignUpDate BETWEEN #pDate AND DATEADD(MONTH, 1, #pDate)-1) AS 'SignUpDate',
COALESCE(SUM(m.ValidCount), 0) AS ValidCount,
COALESCE(SUM(m.InvalidCount), 0) AS InvalidCount
FROM
dbo.Members m
INNER JOIN
dbo.MemberStats ms ON m.MemberID = ms.MemberID
WHERE
m.SignUpdate BETWEEN #pDate AND DATEADD(MONTH, 1, #pDate)-1
The exact syntax depends on the SQL Engine, but if you start with the 1st of the month, then add 1 month, and finally subtract 1 day; you get the end of the month.
(I'll assume MS SQL Server to match your C# tag)
SELECT
*
FROM
members
WHERE
signupdate BETWEEN #param AND DATEADD(MONTH, 1, #param) - 1
If the between isn't required, you can use DatePart.
Untested example:
where DATEPART(yyyy, SignupDate) = 2011 and DATEPART(m, SignupDate) = 7
convert varchar to appropiate format you want and then compare
check the list of formats. Hope this helps dude.
convert date
Firstly, you must convert the string representation to a valid DateTime struct object on the server. You can use var date = DateTime.ParseExact("july 1 2011", "MMMM dd yyyy", CultureInfo.CurrentUICulture) or DateTime.TryParse. Then you pass this into your SqlCommand as parameters. Never use strings when querying, especially when it comes from user input.
I'm generating a line-shift report:
In my application, I'm providing a dropdownlist for selecting shift and line and they will select a date from calender
I have 3 shifts
shift1 starts at 7am and ends at 3pm
shift2 starts at 3pm and ends at 11pm
shift3 starts at 11pm and ends at 3am
I have a table called datalogging where login information will be stored as shown below:
Name Shiftname ID operatorname Date plantname line Machine
Pradeepa Shift2(11-7) 3 Operator 3 2011-05-28 Plant 3 Line5 mc10
Ashwini Shift1(7-3) 1 Operator 1 2011-05-29 Plant 3 Line6 mc12
Deepika Shift2(11-7) 2 Operator 3 2011-05-29 Plant 5 Line9 mc18
Ashwini Shift1(7-3) 1 Operator 1 2011-05-24 Plant 1 Line1 mc1
Deepika Shift2(3-11) 2 Operator 2 2011-05-24 Plant 2 Line3 mc5
Ashwini Shift2(3-11) 1 Operator 2 2011-05-25 Plant 2 Line3 mc5
and so on..
I have a parameter table like temperature,pressure,ph,speed,co2 etc
Temperature table contains following data and this table will contains all the reading from 7am to till 3am
Temperature Time Date
27 13:13:54.000 2011-05-25
27.3 13:14:04.000 2011-05-25
27.6 13:14:14.000 2011-05-25
27.9 13:14:24.000 2011-05-25
28.2 13:14:34.000 2011-05-25
28.5 13:14:44.000 2011-05-25
27 16:13:29.000 2011-05-26
27 16:13:31.000 2011-05-26
and so on..
The user will select a line from dropdownlist and shift and he will select a date from th calender
If the user select shift2,line3 and date 25/05/2011 what are the readings are there between 3pm to 11pm should be displayed in my report
My report should look like:
Machine Shiftname Date Time Temperature
mc5 Shift2 25/05/2011 13:13:54.000 27
mc5 Shift2 25/05/2011 13:14:04.000 27.3
mc5 Shift2 25/05/2011 13:14:14.000 27.6
I'm also doing line-day report
where shiftname should change according to time for eg if time changes to 23:00:00 shiftname should change to shift3 in my report
if the user select particular shift and date for eg if the user selects shift1,line1 and date my report should contain all reading between 7am to 3pm
can any one help me on this.
You could get your report with following query
SELECT d.Machine
, CASE WHEN t.time BETWEEN '19:00:00.000' AND '23:59:59.999' THEN 'Shift1'
WHEN t.time BETWEEN '00:00:00.000' AND '02:59:59.999' THEN 'Shift1'
WHEN t.time BETWEEN '03:00:00.000' AND '10:59:59.999' THEN 'Shift2'
WHEN t.time BETWEEN '11:00:00.000' AND '18:59:59.999' THEN 'Shift3'
END
, t.Date
, t.Time
, t.Temperature
FROM Datalogging d
INNER JOIN Temperature t ON t.Date = d.Date
WHERE d.Shifname = 'Shift2(3-11)'
AND d.Line = 'Line3'
AND t.Date = '25/05/2011'
but if we can assume that each machine would have temperature readings each day, it is clear that there's a relationship missing between your Temperature and Datalogging table.