SQL query to get result for a date range when table got Year and Month fields - sql

I have a table with Year and Month fields. I need to select the rows between two particular dates. How do I set this in the where condition?

You are a bit unclear on what "between" means in this context. I'm pretty sure that datefromparts() can be quite helpful:
select t.*
from t
where #date_start <= datefromparts(year, month, 1) and
#date_end >= datefromparts(year, month, 1);
You might also find eomonth() helpful, if the end of the month is an important date.

You can try with help month(),year() function of date
Here is the example:
select * from t where (t.month=month('2017-01-01') and t.year=year('2017-01-01')) and (t.month=month('2017-05-01') and t.year=year('2017-05-01'));
Below is the link for month() in sql.
https://learn.microsoft.com/en-us/sql/t-sql/functions/month-transact-sql
This might help you in solving your problem.

you can also try something like:
select
d.*
from
(select
t.*,
cast(rtrim(cast([month] as char(2))) + '/1/' + cast ([year] as char(4)) as date) as dt) d
where
dt >= #dateStart and
dt <= #dateEnd

If the year and month values are integers, you can cast them to varchar, then date, and use BETWEEN. An example with declaring startdate and enddate variables:
DECLARE #startdate date = '2015-07-01'
,#enddate date = '2016-07-01'
SELECT *
FROM #myTable
WHERE CAST(CAST(Year as varchar) + '-' + CAST(Month as varchar) + '-01' as date)
BETWEEN #startdate AND #enddate
If they are chars or varchars you need only cast to date and use BETWEEN:
DECLARE #startdate date = '2015-07-01'
,#enddate date = '2016-07-01'
SELECT *
FROM #myTable
WHERE CAST(Year + '-' + Month + '-01' as date)
BETWEEN #startdate AND #enddate

Try with "Between".
Something like this:
SELECT SALES_AMOUNT FROM TABLE WHERE YEAR BETWEEN 2015 AND 2016 AND MONTH BETWEEN 6 AND 8

Related

How to grab data from the last 13 months?

So I have this code, this is for grabbing data for the last 11 month of sale including the current month, make it a whole year. What do I have to do to change it to grabbing data for the last 12 months plus current month? I know I have to change something on the right(select period)... but not sure
In this one, the left function shows how to get the current year (2014 ) minus 1 to give 2013.. but I don't understand the right function, what does 2 mean?
Thanks
period <= (
SELECT Period
FROM dbo.FiscalDates
WHERE (Date = CONVERT(varchar(10), GETDATE(), 102))) and period >= (
convert(varchar, left((
SELECT Period
FROM dbo.FiscalDates
WHERE (Date = CONVERT(varchar(10), GETDATE(), 102))),4)-1)+'-'+
convert(varchar, right((
SELECT Period
FROM dbo.FiscalDates
WHERE (Date = CONVERT(varchar(10), GETDATE(), 102))),2)))
group by prodnum, period, WhseNum
Whoah buddy I think you may be overcomplicating things here. If you want to get data for the past X number of months then just use DATEADD it's a very useful function.
All you need to do then is
select
YourColumns
FROM YourTable
WHERE YourDate >= DATEADD(MONTH, -13, CAST(GETDATE() AS DATE))
and bam there you go.
DECLARE
#FormYear AS INT,
#FormMonth AS INT,
#ToYear AS INT,
#ToMonth AS INT,
#FromDate AS DATE,
#ToDate AS DATE
SET #FormYear=YEAR(DATEADD(DAY, -365, GETDATE()))
SET #FormMonth=MONTH(DATEADD(DAY, -365, GETDATE()))
SET #ToYear=YEAR(GETDATE())
SET #ToMonth=MONTH(GETDATE())
SET #FromDate= CAST(CAST(#FormMonth AS VARCHAR) +'-'+'01'+ '-' +CAST(#FormYear AS VARCHAR) AS DATE)
SET #ToDate= CAST(CAST(#ToMonth AS VARCHAR) +'-' + '01'+'-' + CAST(#ToYear AS VARCHAR) AS DATE)
After that, just select-
YourDateField Between #FormDate AND #ToDate

How to sort varchar string properly with numeric values on both ends?

I'm building a Common Table Expression (CTE) in SQL Server 2008 to use in a PIVOT query.
I'm having difficulty sorting the output properly because there are numeric values that sandwich the string data in the middle. Is it possible to do this?
This is a quick and dirty example, the real query will span several years worth of values.
Example:
Declare #startdate as varchar(max);
Declare #enddate as varchar(max);
Set #startdate = cast((DATEPART(yyyy, GetDate())-1) as varchar(4))+'-12-01';
Set #enddate = cast((DATEPART(yyyy, GetDate())) as varchar(4))+'-03-15';
WITH DateRange(dt) AS
(
SELECT CONVERT(datetime, #startdate) dt
UNION ALL
SELECT DATEADD(dd,1,dt) dt FROM DateRange WHERE dt < CONVERT(datetime, #enddate)
)
SELECT DISTINCT ',' + QUOTENAME((cast(DATEPART(yyyy, dt) as varchar(4)))+'-Week'+(cast(DATEPART(ww, dt) as varchar(2)))) FROM DateRange
Current Output:
,[2012-Week48]
,[2012-Week49]
,[2012-Week50]
,[2012-Week51]
,[2012-Week52]
,[2012-Week53]
,[2013-Week1]
,[2013-Week10]
,[2013-Week11]
,[2013-Week2]
,[2013-Week3]
,[2013-Week4]
,[2013-Week5]
,[2013-Week6]
,[2013-Week7]
,[2013-Week8]
,[2013-Week9]
Desired Output:
,[2012-Week48]
,[2012-Week49]
,[2012-Week50]
,[2012-Week51]
,[2012-Week52]
,[2012-Week53]
,[2013-Week1]
,[2013-Week2]
,[2013-Week3]
,[2013-Week4]
,[2013-Week5]
,[2013-Week6]
,[2013-Week7]
,[2013-Week8]
,[2013-Week9]
,[2013-Week10]
,[2013-Week11]
EDIT
Of course after I post the question my brain started working. I changed the DATEADD to add 1 week instead of 1 day and then took out the DISTINCT in the select and it worked.
DECLARE #startdate AS VARCHAR(MAX);
DECLARE #enddate AS VARCHAR(MAX);
SET #startdate = CAST((DATEPART(yyyy, GetDate())-1) AS VARCHAR(4))+'-12-01';
SET #enddate = CAST((DATEPART(yyyy, GetDate())) AS VARCHAR(4))+'-03-15';
WITH DateRange(dt) AS
(
SELECT CONVERT(datetime, #startdate) dt
UNION ALL
SELECT DATEADD(ww,1,dt) dt FROM DateRange WHERE dt < CONVERT(datetime, #enddate)
)
SELECT ',' + QUOTENAME((CAST(DATEPART(yyyy, dt) AS VARCHAR(4)))+'-Week'+(CAST(DATEPART(ww, dt) AS VARCHAR(2)))) FROM DateRange
I can't see the sample SQL code (that site is blacklisted where I am).
Here is a trick for sorting that data in the proper order is to use the length first and then the values:
select col
from t
order by left(col, 6), len(col), col;
Have you considered to sort on two temporary columns (year in smallint and week in tinyint to save space … or directly using the datepart integer if space is not a problem to you and you prefer fast run) along with the use of "order by year, week" ?
If you store dates using a more suitable type (what I suggest), it would then become :
WITH [Define the CTE expression name and column list]
AS
(
SELECT CAST(DATEPART(yyyy, dt) as smallint(4)) year, cast(DATEPART(ww, dt) as tinyint(2)) week, [your columns here]
FROM DateRange WHERE dt < #enddate
)
[Define the outer query referencing the CTE name]
ORDER BY year, week;
GO
Also, please note that string operations will slow your queries so avoid them when possible !
I like Gordon's answer, but if you were hell-bent on text manipulation in your order by:
ORDER BY CAST(REPLACE(LEFT('[2012-Week48]',5),'[','')AS INT)
,CAST(REPLACE(RIGHT('[2012-Week48]',CHARINDEX('Week','[2012-Week48]')-4),']','') AS INT)
Here is another option converting the beginning and ending parts of the column to integer.
SELECT *
FROM YourTable
ORDER BY CAST(SUBSTRING(yourcolumn,1,4) as int),
CAST(SUBSTRING(yourcolumn,CHARINDEX('Week',yourcolumn)+4,len(yourcolumn)) as int)
SQL Fiddle Demo
This will work assuming the format of the data is always the same.
Since you are using dt to generate the string, you should sort by using the date's parts:
WITH DateRange(dt) ...
SELECT DISTINCT ',' + QUOTENAM...
ORDER BY DATEPART(yyyy, dt), DATEPART(ww, dt)
I needed to change the DATEADD portion of the query and remove the DISTINCT. Once changed the order sorted properly on it's own
DECLARE #startdate AS VARCHAR(MAX);
DECLARE #enddate AS VARCHAR(MAX);
SET #startdate = CAST((DATEPART(yyyy, GetDate())-1) AS VARCHAR(4))+'-12-01';
SET #enddate = CAST((DATEPART(yyyy, GetDate())) AS VARCHAR(4))+'-03-15';
WITH DateRange(dt) AS
(
SELECT CONVERT(datetime, #startdate) dt
UNION ALL
SELECT DATEADD(ww,1,dt) dt FROM DateRange WHERE dt < CONVERT(datetime, #enddate)
)
SELECT ',' + QUOTENAME((CAST(DATEPART(yyyy, dt) AS VARCHAR(4)))+'-Week'+(CAST(DATEPART(ww, dt) AS VARCHAR(2)))) FROM DateRange

SQL - Sum of minutes between two timestamps by month

I am looking for an SQL query for the sum of minutes between start and end date for a particular month.
Eg.
I'm looking for the amount of minutes used in February.
Start Date Time: 27-02-13 00:00:00
End Date Time: 05-03-13 00:00:00
Because im only looking for the sum of february it should only give me the sum of 3 days (in minutes) and not the extra 5 days going into march.
I have no way to validate it but it should looks like:
SELECT DATEDIFF(minute, startDate, CASE when endDate > EOMONTH(startDate) THEN EOMONTH(startDate) ELSE endDate END) FROM ...
GL!
I left it in steps to illustrate each process. You can of course easily collapse this down, but I'll leave it up to you to do that.
Here's my solution http://www.sqlfiddle.com/#!3/b4991/1/0
SELECT *
, DATEDIFF(minute, StartDAte, NewEndDate) AS TotalMinutes
FROM
(
SELECT *
, CASE WHEN TempDate > EndDate THEN EndDate ELSE TempDate END AS NewEndDate -- Either EOM or old EndDate, whichever is smaller
FROM
(
SELECT *
, DATEADD(month, 1, CAST(Year + '-' + Month + '-1' AS DATETIME)) AS TempDate -- first day of the next month
FROM
(
select *
, CAST(DATEPART(month, StartDate) AS char(2)) AS Month
, CAST(DATEPART(year, StartDate) AS char(4)) AS Year
from tbl
) t0
) t1
) t2
First I get the year and month from the original StartDate. I then construct a first-of-the-month date from that. I then add one month to that to get me the first-of-the-month of the next month. Then I check if that new date is > or < the previous EndDate. I take the smaller of the two dates. Then I use the original StartDate and whichever is smaller between the TempDate and EndDate to determine my total minutes.
See Also EOMONTH: http://msdn.microsoft.com/en-us/library/hh213020.aspx
Look into using DATEDIFF -- this will just help you to get started:
SELECT DATEDIFF(minute, starttime, endtime)
http://msdn.microsoft.com/en-us/library/ms189794.aspx
To get the last day of the start month, use DATEADD:
SELECT DATEADD(second,-1,DATEADD(month, DATEDIFF(month,0,starttime)+1,0))
SQL Fiddle Demo
I recently had to solve a similar problem, I added two new functions to help with this:
CREATE FUNCTION [dbo].[GREATESTDATE]
(
-- Add the parameters for the function here
#Date1 DATETIME,
#Date2 DATETIME
)
RETURNS DATETIME
AS
BEGIN
IF (#Date1 < #Date2)
RETURN #Date2
ELSE
RETURN #Date1
END
and...
CREATE FUNCTION [dbo].[LEASTDATE]
(
-- Add the parameters for the function here
#Date1 DATETIME,
#Date2 DATETIME
)
RETURNS DATETIME
AS
BEGIN
IF (#Date1 > #Date2)
RETURN #Date2
ELSE
RETURN #Date1
END
Then use them like:
DATEDIFF(D,dbo.GREATESTDATE(#StartDate1,#StartDate2),dbo.LEASTDATE(#EndDate1,#EndDate2))

SQL Server 2008 select data only between month and year

I would like select data between two date, without day
An input example:
start month: 9 , start year: 2011
end month: 3, end year: 2012
I think that there are two way to do this.
The first is convert start month and start year to date like 2011-09-01 and convert last date to 2012-03-31, but this requires calculation of the last day of end month. Obtained these date we can use a BEETWEN function for the WHERE clause (but, is the CONVERT function reliable?)
The second solution is to use the DATEPART function like in the following code:
I try to explain: if end year is equal to the initial year, then month must be between the start and end months; else if the final months is greater than the initial years if different from the initial and final year, I take everything in between; else if the final year, the month must be less than or equal to the final month, if the initial year, month must be greater than or equal to the final month
Can you help me do this in the best way? Is correct, the solution I adopted?
declare #IndDebitoCredito bit,#ProgTributo int,#mi as integer,#ai as integer,#mf as integer,#af as integer,#IDAnagrafica varchar(5)
select #mi = 01,#ai = 2011,#mf = 12,#af = 2011,#IDAnagrafica = 'DELEL',#IndDebitoCredito = 1
select distinct rrd.IDTributo
from TBWH_Delega d
--inner join TBWH_SezioneDelega sd on d.IDDelega = sd.IDDelega
inner join TBWH_Rigo rd on rd.IDDelega = d.IDDelega
inner join TBWH_RataRigo rrd on rrd.IDRigo = rd.IDRigo
where
(
DATEPART(MM,d.DataDelega)<=#mf and
DATEPART(MM,d.DataDelega)>=#mi and
DATEPART(YYYY,d.DataDelega)=#ai and
#af = #ai
)
OR
(
--anno finale magg. anno iniziale
#af > #ai AND
(
( -- delega nell'intervallo
DATEPART(YYYY,d.DataDelega)<#af AND
DATEPART(YYYY,d.DataDelega)>#ai
-- DATEPART(MM,d.DataDelega)>=#mi
)
OR
( -- delega limite destro
DATEPART(YYYY,d.DataDelega)=#af AND
DATEPART(MM,d.DataDelega)<=#mf
)
OR
( -- delega limite sinistro
DATEPART(YYYY,d.DataDelega)=#ai AND
DATEPART(MM,d.DataDelega)>=#mi
)
)
)
GO
Your first solution is almost there, but is more complicated than it needs to be and won't work anyway. It will miss out any rows from the last day of the end month.
You can add one month to the end month and then use BETWEEN on the first of each month. eg.
start month: 9 , start year: 2011
end month: 3, end year: 2012
BETWEEN '2011-09-01' AND '2012-04-01'
or, as JNK points out, this will be better:
DataDelega >= '2011-09-01' AND DataDelega < '2012-04-01'
You'll need to add in some logic to deal with the end month being December, but this looks like the simplest way of doing it.
You are WAY overcomplicating this. You really only need two comparisons:
Is the month and year after or equal to the initial value?
Is the month and year before or equal to the final value?
Try:
SELECT *
FROM MyTable
WHERE Datefield BETWEEN
CAST(#mi as varchar) + '/1/' + CAST(#ai as varchar)
-- first of first month
AND
DATEADD(DAY, -1, (DATEADD(Month, + 1, (CAST(#mf as varchar) + '/1/' + CAST(#af as varchar)))))
-- Last day or final month
SELECT *
FROM Table
WHERE DateField
BETWEEN CONVERT(DATE, CONVERT(CHAR(4), #ai) + RIGHT('00' + CONVERT(VARCHAR(2), #mi), 2) + '01', 112)
AND DATEADD(DD, -1, DATEADD(MM, 1, CONVERT(DATE, CONVERT(CHAR(4), #af) + RIGHT('00' + CONVERT(VARCHAR(2), #mf), 2) + '01', 112)))
Avoid using expressions on the DateField columns, as it makes query not SARGable.
I would use:
WHERE DateToCheck >= --- first day of StartMonth
DATEADD( mm, #StartMonth-1,
DATEADD( yy, #StartYear-2000, '2000-01-01')
)
AND DateToCheck < --- first day of next month (after EndMonth)
DATEADD( mm, #EndMonth,
DATEADD( yy, #EndYear-2000, '2000-01-01')
)
DECLARE #mi INT
, #ai INT
, #mf INT
, #af INT
SELECT #mi = 01
, #ai = 2011
, #mf = 12
, #af = 2011
--local variables to hold dates
DECLARE #i DATETIME
, #f DATETIME
--build strings to represent dates in YYYYMMDD format
--add a month to the #f date
SELECT #i = CONVERT(VARCHAR(4), #ai) + RIGHT('0' + CONVERT(VARCHAR(2), #mi),
2) + '01'
, #f = DATEADD(month, 1,
CONVERT(VARCHAR(4), #af) + RIGHT('0'
+ CONVERT(VARCHAR(2), #mf),
2) + '01')
--select data where date >= #i, and < #f
SELECT *
FROM MyTable
WHERE DateField >= #i
AND DateField < #f

Select records from start of month to current date

I'm trying to select records that were added to the database between the start of the current month and the current day - I more or less know how to get records from the current day, and within a specific time period - but how do I get it so it starts from the beginning of the current calendar month?
DECLARE #sm DATETIME;
SET #sm = DATEADD(DAY, 1-DAY(GETDATE()), DATEDIFF(DAY, 0, GETDATE()));
SELECT columns
FROM dbo.foo
WHERE datetime_column >= #sm;
WHERE YEAR([Date])=YEAR(GETDATE())
AND MONTH([Date])=MONTH(GETDATE())
AND DAY([Date])<=DAY(GETDATE())
select *
from YourTable
where DateCol >= dateadd(month, datediff(month, 0, getdate()), 0)
Basically what you're doing here is Getting the Month, appending '/01' and then appending the year. Casting it as a string to handle the appending, then casting it as a DateTime.
So it's a little bit more involved than doing any sort of date math, but it's readable I think.
DECLARE #firstOfMonth DATETIME
SET #firstOfMonth = CAST(CAST(DATEPART(mm, GetDate()) as varchar) + '/01/' + cast(DATEPART(yyyy, Getdate()) as varchar) as datetime)
WHERE DateToCheck BETWEEN #firstOfMonth and GetDate()
WHERE DateToCheck > LAST_DAY(CURDATE()-INTERVAL 1 MONTH))
http://www.sqlfiddle.com/#!2/3d673/2/0