I have a sql query that is grouping rows by calendar week
select count(*),datepart(wk,mydate)
from MyTable
where mydate between '12/26/2010' and '1/8/2011'
group by datepart(wk,mydate)
The date range is two weeks but three rows come back because Jan 1 is a saturday and is the only day in the range that DATEPART returns a 1 the other dates return 53 or 2.
I want jan 1 to be grouped with the dates that return a 53, but I want it to be a generic answer not something like CASE WHEN datepart(wk,mydate) = 53 then 1 else datepart(wk,mydate) end because that will work for that specific date range not for other years.
I'm just wondering what a good solution would be
thanks in advance.
We use to choose as week of a date, the week of his last sunday (first day of the week in SQL). So, for each date, you can ask for the week of his last sunday with the following query:
select count(*),datepart(wk,mydate-DATEPART(dw,mydate)+1)
from MyTable
where mydate between '12/26/2010' and '1/8/2011'
group by datepart(wk,mydate-DATEPART(dw,mydate)+1)
Perhaps you can use iso_week instead of wk.
select count(*),datepart(iso_week,mydate)
from MyTable
where mydate between '12/26/2010' and '1/8/2011'
group by datepart(iso_week,mydate)
Sample:
declare #T table (Val datetime)
insert into #T values
('2010-12-30'),
('2010-12-31'),
('2011-01-01'),
('2011-01-02'),
('2011-01-03'),
('2011-01-04'),
('2011-01-05')
select
Val,
datepart(iso_week, Val) as ISO_WEEK
from #T
Result:
Val ISO_WEEK
----------------------- -----------
2010-12-30 00:00:00.000 52
2010-12-31 00:00:00.000 52
2011-01-01 00:00:00.000 52
2011-01-02 00:00:00.000 52
2011-01-03 00:00:00.000 1
2011-01-04 00:00:00.000 1
2011-01-05 00:00:00.000 1
Try DateDiff() instead with your start date as the date to compare.
Related
Snowflake has the simply function Quarter(timestamp()) which returns current quarter, but wondering how to do day of QTR , all tutorials reference Postgres/ sql server.
Goal - create a date table, and show what day of the quarter it is for the next 20 years.
SELECT column1::timestamp as d,
DATE_TRUNC('QUARTER',d) as q,
DATEDIFF('day',q, d) as doq
FROM VALUES ('2019-10-30'),('2019-10-01');
gives 0 for the first day of the quarter, so if you need that to be 1 you can +1 that datadiff.
D Q DOQ
2019-10-30 00:00:00.000 2019-10-01 00:00:00.000 29
2019-10-01 00:00:00.000 2019-10-01 00:00:00.000 0
[Edit:] After re-reading your goal of a 20 year table, here is some code I have used in snowflake in the past to just that:
CREATE OR REPLACE TABLE twenty_years_of_days(date) AS
SELECT DATEADD(day, rn, CURRENT_DATE) as date,
DATE_TRUNC('QUARTER',date) as quarter,
DATEDIFF('day',quarter, date) as doq
FROM (
SELECT row_number() over(order by 1) as rn
FROM TABLE(GENERATOR(rowCount => 365*20)) v
);
I am new to SQL server and was practising using Sachin's batting stats (Cricket) I found here. (Sachin Batting Statistics). I wanted to find the longest gap between two test matches in Sachin's career. So basically have to filter it based on Test matches and find the max difference in the Start_DateAscending column? Hope that made some sense. Sample table added if link doesn't make sense
EDIT: I created a sample table with different dates. the column is named DateValues. Now, I want to find the code for maximum difference between any two successive rows in the DateValue column. For example, in this case the answer is 2 years and 17 days between December 09, 1989 and December 26, 1991
IF OBJECT_ID('TempDB..#mytable','U') IS NOT NULL
DROP TABLE #mytable
CREATE TABLE #mytable
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
DateValue DATETIME
)
SET DATEFORMAT DMY
SET IDENTITY_INSERT #mytable ON
INSERT INTO #mytable
(ID, DateValue)
SELECT '11', 'Nov 15 1989 12:00AM' UNION ALL
SELECT '59', 'Nov 23 1989 12:00AM' UNION ALL
SELECT '37', 'Dec 09 1989 12:00AM' UNION ALL
SELECT '44', 'Dec 26 1991 12:00AM' UNION ALL
SELECT '55', 'May 31 1993 12:00AM' UNION ALL
SELECT '60', 'May 15 1995 12:00AM' UNION ALL
SELECT '57', 'Jan 12 1996 12:00AM' UNION ALL
SELECT '43', 'Jan 19 1996 12:00AM' UNION ALL
SELECT '49', 'Jan 31 1996 12:00AM' UNION ALL
SELECT '18', 'Oct 17 1997 12:00AM'
Here's a solution I found on this website, the answer I obtained was 1900-01-01!
SELECT MAX(#mytable.DateValue-h.DateValue) as maxDiff
FROM #mytable
LEFT JOIN #mytable h
ON h.ID=[dbo].#mytable.ID AND #mytable.DateValue>=h.DateValue
WHERE h.DateValue IS NOT NULL
If you're using SQL Server 2012 or above, this SQL will return the biggest gap in days between two tests:
select max(datediff(day, a.TestDate, a.NextTest)) as BiggestGap
from (
select DateValue as TestDate, lead(DateValue) over (order by DateValue) as NextTest
from #mytable m
) a
The first thing this query does (inside the parenthesis) is gets a table that lists all test matches and the date of the next test match. That's what the innermost query provides: It selects all test dates and, using the lead function, the date of the match straight after that test.
The data from that parenthesised select (including ID) looks like this:
ID TestDate NextTest
----------- ----------------------- -----------------------
11 1989-11-15 00:00:00.000 1989-11-23 00:00:00.000
59 1989-11-23 00:00:00.000 1989-12-09 00:00:00.000
37 1989-12-09 00:00:00.000 1991-12-26 00:00:00.000
44 1991-12-26 00:00:00.000 1993-05-31 00:00:00.000
55 1993-05-31 00:00:00.000 1995-05-15 00:00:00.000
60 1995-05-15 00:00:00.000 1996-01-12 00:00:00.000
57 1996-01-12 00:00:00.000 1996-01-19 00:00:00.000
43 1996-01-19 00:00:00.000 1996-01-31 00:00:00.000
49 1996-01-31 00:00:00.000 1997-10-17 00:00:00.000
18 1997-10-17 00:00:00.000 NULL
After that (outside the parenthesis), it's simply a case of finding the row with the biggest difference between dates. In SQL Server, it's best to use the datediff function to get the difference between two dates instead of using mathematical operators such as - in the example you saw, so we use that to get the difference in days between each row. max is used to get the largest of those, thus returning the biggest gap between two matches.
Using the example SQL data provided, the biggest gap is 747 days (approximately 2 years 17 days).
ID DateTime Code
---------- -------------- ----------
58 2015-01-01 20:00:00 1111
58 2015-01-11 10:00:00 8523
58 2015-01-11 03:00:00 4555
58 2015-01-19 00:01:00 8888
9 2015-01-01 20:00:00 4444
how do i count the number of codes for a specific ID ignoring which date it is but it must be between 20:00:00 and 06:00:00
select count(code) as count from table 1 where ID='58' and DateTime between '20:00:00' and '06:00:00'
the expected output would be
count
3
SELECT count(code) as count
FROM table1
WHERE
ID='58' and
(CAST(DateTime as time) >= '20:00'
or CAST(DateTime as time) <= '06:00')
EDIT: John, I understand the issue. Here is a full solution to handle those cases:
In order to use variables:
DECLARE #HourBegin time = '07:00'
DECLARE #HourEnd time = '17:30'
SELECT count(code) as count
FROM table1
WHERE
ID='58' and
(CAST(DateTime as time) between #HourBegin and #HourEnd or
((CAST(DateTime as time) <= #HourEnd or
CAST(DateTime as time) >= #HourBegin) and
#HourBegin > #HourEnd)
)
Almost the same as previous answer, but with hours it looks nicer for me and might be you need DISTINCT code
SELECT count(DISTINCT code) as count
FROM table1
WHERE
ID='58' and
(DATEPART(HOUR,DateTime) >= 20
or DATEPART(HOUR,DateTime) < 6)
UPDATED: changed from <= 6 to < 6
Update
This answer applies to MySQL.
When I started writing the answer, the question was tagged mysql and sql-server. The OP edited it in the meantime.
This query should do what you want on MySQL.
SELECT count(code) AS `count`
FROM `table 1`
WHERE ID='58'
AND TIME(`DateTime`) NOT BETWEEN '06:00:01' AND '19:59:59'
The MySQL function TIME() extracts only the time component from a DATETIME value.
On version 5.7, MySQL added support for fractional seconds (up to 6 digits) on DATETIME columns. The query above will include the entries having time greater than 06:00:00 but smaller than 06:00:01 (events that happened during the first second after 6 AM sharp).
For MySQL 5.7 and newer, the correct query is:
SELECT count(code) AS `count`
FROM `table 1`
WHERE ID='58'
AND (TIME(`DateTime`) <= '06:00:00' OR '20:00:00' <= TIME(`DateTime`))
I don't know about SQL Server.
I have a table of data similar to below where I need to calculate the sum of all the paused time up until today. The columns can have any date in them, so PauseStart can be a future date , and PauseEnd can also be a future date. A Null date (20991231) is considered open ended, i.e. no end date to the pause was selected.
NB : Dates are UK date format
The data
PauseID RecID PauseStart PauseEnd
1022 10 2013-01-04 15:52:04.320 2013-01-21 00:00:00.000
1023 10 2013-01-01 00:00:00.000 2013-01-02 00:00:00.000
1024 10 2013-01-05 00:00:00.000 2099-01-01 00:00:00.000
The data above shows that we had a pause between 1/1/2013 and 2/1/2013, a pause between 4/1/2013 and 21/1/2013 (which should register in the sum as 4/1/2013 to 7/1/2013 11:00:00) and 5/1/2013 -> open (which should register in the sum as 5/1/2013 to 7/1/2013 11:00:00)
The columns are not indexed.
The TSQL which I have come up with looks like this
SELECT
SUM (
CASE
WHEN NULLIF(PauseEnd,'20991231') IS NULL THEN
DATEDIFF(mi, PauseStart, ISNULL(NULLIF(PauseEnd,'20991231'), GetDate()))
WHEN PauseEnd > GetDate() THEN
DATEDIFF(mi, PauseStart, GetDate())
ELSE
DATEDIFF(mi, PauseStart, ISNULL(NULLIF(PauseEnd,'20991231'), GetDate()))
END
) AS Datedifference
FROM Pauses
WHERE Pauses.RecID = 10
AND PauseStart < GetDate()
This gives me the results
4021
1440
3533
which seem correct, however my question remains,
Is this the most efficient way of achieving this result?
addendum, this table could start holding millions of records, so I'd like to make the tsql that calculates the sum efficient in the first instance.
I would do it like this:
SELECT
PauseStart,
DATEDIFF(mi, PauseStart, CASE WHEN PauseEnd > GetDate() THEN GetDate() ELSE PauseEnd END) as Datedifference
FROM Pauses
WHERE Pauses.RecID = 10 AND PauseStart < GetDate()
I need to get the week number of the giving date. For Ex jan 1 = week no is 1, Jan 8 - week 2 like this.. any one help me out pls.
You should try something like this:
DECLARE #Dt datetime
SELECT #Dt='02-21-2008'
SELECT DATEPART( wk, #Dt)
This should return the weeknumbers you want.
SQL Server starts counting from the 1st of january. If you want to return the ISO weeknumbers, you need to do a bit more scripting. A nice howto is listed in this site: http://www.rmjcs.com/SQLServer/TSQLFunctions/ISOWeekNumber/tabid/207/Default.aspx
MSDN: DATEPART (Transact-SQL)
In response to Robin's comment:
But i need in such a way, that from
jan 1 to 7, it should return 1, from
jan 8 to 17 it should return 2 like
this.. hope u got my impression
In that case you could also write something like this.
select (datepart(dy, '2011-01-01') / 7) + 1
--returns 1
select (datepart(dy, '2011-01-02') / 7) + 1
--returns 1
select (datepart(dy, '2011-12-31') / 7) + 1
--returns 53
I don't know how SQL Server 2008 responds with the iso_week and wk parameter as I only got a SQL 2005 instance available at the moment.
Does this do what you want?
declare #T table (dt datetime)
insert into #T values
('2010-12-31'),
('2011-01-01'),
('2011-01-02'),
('2011-01-03'),
('2011-01-04'),
('2011-01-05'),
('2011-01-06'),
('2011-01-07'),
('2011-01-08')
select
dt,
(datediff(d, dateadd(year, datediff(year, 0, dt), 0), dt) / 7)+1
from #T
Result
dt
----------------------- -----------
2010-12-31 00:00:00.000 53
2011-01-01 00:00:00.000 1
2011-01-02 00:00:00.000 1
2011-01-03 00:00:00.000 1
2011-01-04 00:00:00.000 1
2011-01-05 00:00:00.000 1
2011-01-06 00:00:00.000 1
2011-01-07 00:00:00.000 1
2011-01-08 00:00:00.000 2