Swap date fields when one date is less than the other - tsql

I am attempting to flip date fields as for some reason the people who sent the data to us has them in the wrong fields. Essentially whenever revived_date is greater than JDate they need to be flipped around. I attempted the code below and it said it corrects 2341 fields and then I run a select and it shows no records found but when looking at the data I clearly see wrong data.
UPDATE defendants_ALL_backup
SET JDate = revived_date, revived_date = JDate
WHERE convert(varchar,JDate, 101) < convert(varchar, revived_date, 101);
If I select the top 1000 rows the first 3 are wrong and look like this so it obviously doesn't work.
JDate revived_date
2011-04-14 00:00:00.000 1986-02-11 00:00:00.000
2011-04-14 00:00:00.000 1986-02-11 00:00:00.000
2011-04-14 00:00:00.000 1986-02-11 00:00:00.000
Any ideas?

Assuming that you have uniqnue ID and the first date should be smaller then the second one:
DECLARE #DataSource TABLE
(
[ID] TINYINT
,[DateOne] DATETIME2
,[DateTwo] DATETIME2
)
INSERT INTO #DataSource ([ID], [DateOne], [DateTwo])
VALUES (1, '1986-02-11 00:00:00.000', '2011-04-14 00:00:00.000')
,(2, '2013-02-11 00:00:00.000', '2011-04-14 00:00:00.000')
,(3, '2012-02-11 00:00:00.000', '2011-04-14 00:00:00.000')
,(4, '2011-05-11 00:00:00.000', '2011-04-14 00:00:00.000')
,(5, '1986-02-11 00:00:00.000', '2011-04-14 00:00:00.000')
;WITH DataForFix ([ID], [DateOne], [DateTwo]) AS
(
SELECT [ID]
,[DateOne]
,[DateTwo]
FROM #DataSource
WHERE [DateOne] > [DateTwo]
)
UPDATE #DataSource
SET [DateOne] = DFF.[DateTwo]
,[DateTwo] = DFF.[DateOne]
FROM #DataSource DS
INNER JOIN DataForFix DFF
ON DS.[ID] = DFF.[ID]
SELECT [ID]
,[DateOne]
,[DateTwo]
FROM #DataSource

In the three example rows you have listed, the JDate is already greater than the revived_date, so those records would not have be swapped because of your WHERE clause.
You are comparing to varchars, which will to a comparison alphabetically. If you are wanting to compare the values as dates, they don't need to be converted to anything else
UPDATE defendants_ALL_backup
SET JDate = revived_date, revived_date = JDate
WHERE JDate < revived_date

Related

Comparison of two rows in TSQL

Good Day
I have the following result set returned:
financeYearEnd FromDate ToDate ClientPortfolioCode
2013-12-31 00:00:00.000 2014-01-01 2014-01-31 C1
2013-12-31 00:00:00.000 2014-01-01 2014-01-31 C2
2012-12-31 00:00:00.000 2013-12-01 2013-12-31 C1
2012-12-31 00:00:00.000 2013-12-01 2013-12-31 C2
What I need to do is the following:
I need to compare the financeYearEnd of all the C1 Fields (there will always only be two), and see if they are different to each other
2013-12-31 00:00:00.000 2014-01-01 2014-01-31 C1
2012-12-31 00:00:00.000 2013-12-01 2013-12-31 C1
As seen, the financeYearEnd does differ, so I need to store that result as a row in a temporary Table.
This needs to be done for all distinct ClientPortfolioCodes(Which will always appear in groups of two)
How can this be achieved?
I have tried select distinct .. - didn't work. It returned all my rows
EDIT -
WITH cteCompareTopTwoYears
AS (
SELECT TOP (
SELECT COUNT(*) * 2
FROM #ClientPortFolios
) FinancialYearEnd AS financeYearEnd
,FromDate
,ToDate
,CA.ClientPortfolioCode
FROM rpt.F3_fn_ClientPortfolios_CapitalAccount_IncludingYTD CA
WHERE (
(
CA.FromDate = (DATEADD(m, - 1, #FromDate))
AND CA.ToDate = (DATEADD(m, - 1, #ToDate))
)
OR (
CA.FromDate = #FromDate
AND CA.ToDate = #ToDate
)
)
AND (
CA.ClientPortFolioCode IN (
SELECT ClientPortfolioCode
FROM #ClientPortfolios
)
)
ORDER BY FromDate DESC
)
SELECT *
FROM cteCompareTopTwoYears c
Perhaps with the help of ROW_NUMBER, e.g.:
WITH CTE AS
(
SELECT financeYearEnd, FromDate, ToDate, ClientPortfolioCode,
rn = row_Number () OVER (Partition By ClientPortfolioCode
Order By financeYearEnd ASC)
FROM dbo.TableName
)
SELECT financeYearEnd, FromDate, ToDate, ClientPortfolioCode
FROM CTE
WHERE rn > 1
Demo

T-SQL get months from ranges of date

I have a Table with id and start date and end date. i want insert into another table, end of each month between the start data and end date and the ID, e.g.
ID Start Date End Date
1 2012-01-01 2012-03-31
2 2012-10-01 2012-12-31
Results
ID MONTH END
1 2012-01-31
1 2012-02-29
1 2012-03-31
2 2012-10-31
2 2012-11-30
2 2012-12-31
This answer makes some assumptions - no end-dates greater than start-dates, but you should see how it works. It creates a recursive union CTE and uses that to figure out the end dates
CREATE TABLE #Dates
(
ID INT IDENTITY PRIMARY KEY,
START_DATE DATETIME2(0) NOT NULL,
END_DATE DATETIME2(0) NOT NULL
)
INSERT INTO #Dates VALUES ('2012-01-01', '2012-03-31'), ('2012-10-01','2012-12-31')
WITH MONTHS ([ID],[Month],[Date], [End])
AS
(
SELECT ID, DATEPART(m,START_DATE) AS [Month], START_DATE AS [Date], DATEADD(s,-1,DATEADD(m,DATEDIFF(m,0,START_DATE)+1,0)) as [End]
FROM #Dates
UNION ALL
SELECT D.ID, DATEPART(m,DATEADD(m,1,[Date])),DATEADD(m,1,[Date]), DATEADD(s,-1,DATEADD(m,DATEDIFF(m,0,DATEADD(m,1,[Date]))+1,0)) as [End]
FROM #Dates D
INNER JOIN MONTHS M
ON D.ID = M.ID
WHERE DATEADD(m,1,[Date]) < [END_DATE]
)
SELECT *
FROM MONTHS ORDER BY ID, Date
DROP TABLE #Dates

Calculation of total duration of events for a day

We have a table called Events, with columns Id(int), EventDate(DateTime), EventStart(datetime) and EventEnd(datetime).
All events start and end on a single day (i.e. no events end the next day), however events in a given date may overlap between them (including one of them could cover another entirely).
Any number of events may occur for a given date.
I would like to, for a single day calculate the total duration during which at least one event was running in T-SQL. I can select the events on a given date, and have even written a function returning true if two events are overlapping and false if not.
I am stuck however in how to take the records in pairs and run them through my function, adding the durations appropriately until I run out of events.
Can you help?
Chris
Try this:
--test table
declare #t table(fromt datetime, tot datetime)
--test data
insert #t values('2011-01-01 10:00', '2011-01-01 11:00')
insert #t values('2011-01-01 10:00', '2011-01-01 10:05')
insert #t values('2011-01-01 10:30', '2011-01-01 11:30')
insert #t values('2011-01-01 12:00', '2011-01-01 12:30')
insert #t values('2011-01-02 12:00', '2011-01-02 12:30')
--query
;with f as
(
select distinct fromt from #t t
where not exists(select 1 from #t where t.fromt > fromt and t.fromt < tot)
), t as
(
select distinct tot from #t t
where not exists(select 1 from #t where t.tot >= fromt and t.tot < tot)
), s as
(
select datediff(day, 0, fromt) d, datediff(second, fromt, (select min(tot)
from t where f.fromt < tot and datediff(day, f.fromt, tot) = 0)) sec
from f
)
select dateadd(day, 0, d) day, sum(sec)/60 [minutes]
from s
group by d
order by d
Result:
day minutes
----------------------- -------
2011-01-01 00:00:00.000 120
2011-01-02 00:00:00.000 30

Understanding TSQL Coalesce function

I am trying to select all 12 months / year. And I thought following TSQL code would do this. However, this does not include all months like I want. What is the cause of this? This is modified code:
DECLARE #END_YEAR VARCHAR(10)
DECLARE #END_MONTH VARCHAR(10)
SET #END_YEAR = '2010'
SET #END_MONTH = '10'
DECLARE #TheMonthLastDate DATETIME
DECLARE #TempDate DATETIME
SET #TempDate = '2010-11-01 00:00:00.000'
SET #TheMonthLastDate = '2010-11-01 00:00:00.000'
;with months
as
(
select dateadd(month, -1, dateadd(day, datediff(day, 0, #TempDate), 0)) as m
union all
select dateadd(month, -1, m)
from months
where m > dateadd(month, -12, #TempDate)
)
,yourTable(DateOpened, DateClosed)
as
(select TSK_START_DATE, BTK_CLOSED_DATE
FROM [PROC].ALL_AUDIT
WHERE
(BTK_CLOSED_DATE < #TheMonthLastDate OR
TSK_START_DATE < #TheMonthLastDate
)
)
select yt.DateClosed 'r2', m.m 'r3',
month(coalesce(yt.DateClosed, m.m)) as 'MonthClosed',
year(coalesce(yt.DateClosed, m.m)) as 'YearClosed'
from months m
left join yourTable yt
on
( datepart(year, yt.DateClosed) = DATEPART(year, m.m)
and datepart(month, yt.DateClosed) = DATEPART(month, m.m)
or
datepart(year, yt.DateOpened) = DATEPART(year, m.m)
and datepart(month, yt.DateOpened) = DATEPART(month, m.m)
)
AND year(coalesce(yt.DateClosed, m.m)) = 2010
order by yt.DateClosed
So above query does not return all months. But if I change above WHERE lines to:
FROM [PROC].ALL_AUDIT
WHERE
BTK_CLOSED_DATE < #TheMonthLastDate
then this query does return all 12 months. How can this be?
Output that I want and that I see when WHERE is BTK_CLOSED_DATE < #TheMonthLastDate:
r2 r3 MonthClosed YearClosed
NULL 2010-06-01 00:00:00.000 6 2010
NULL 2009-11-01 00:00:00.000 11 2009
2010-01-06 20:02:19.127 2010-01-01 00:00:00.000 1 2010
2010-01-27 23:13:45.570 2010-01-01 00:00:00.000 1 2010
2010-02-15 14:49:14.427 2010-02-01 00:00:00.000 2 2010
2010-02-15 14:49:14.427 2009-12-01 00:00:00.000 2 2010
But if I instead use WHERE:
(BTK_CLOSED_DATE < #TheMonthLastDate OR
TSK_START_DATE < #TheMonthLastDate
)
then I see:
r2 r3 MonthClosed YearClosed
NULL 2010-10-01 00:00:00.000 10 2010
NULL 2010-09-01 00:00:00.000 9 2010
NULL 2010-09-01 00:00:00.000 9 2010
NULL 2010-08-01 00:00:00.000 8 2010
NULL 2010-08-01 00:00:00.000 8 2010
...
So notice that in first result I see NULL for June 2010, which is what I want.
I think the problem has something to do with the fact that my data contains 2009-2011 data, but I only compare months and not years. How would I add in this additional logic?
The only place where you are reducing the data is with the WHERE clause you have already identified. Therefore, the reason you are not getting all the months you expect is down to the column TSK_START_DATE not being less than #TheMonthLastDate for all months.
To prove this hypothesis, run the following section of your query (I have commented out part of the where clause and removed everything under 'yourTable' cte). The results should show you what is being returned in the TSK_Start_Date column for your missing months and help you identify why the rows are missing when applying the < #TheMonthLastDate clause.
DECLARE #END_YEAR VARCHAR(10)
DECLARE #END_MONTH VARCHAR(10)
SET #END_YEAR = '2010'
SET #END_MONTH = '10'
DECLARE #TheMonthLastDate DATETIME
DECLARE #TempDate DATETIME
SET #TempDate = '2010-11-01 00:00:00.000'
SET #TheMonthLastDate = '2010-11-01 00:00:00.000'
;with months
as
(
select dateadd(month, -1, dateadd(day, datediff(day, 0, #TempDate), 0)) as m
union all
select dateadd(month, -1, m)
from months
where m > dateadd(month, -12, #TempDate)
)
,yourTable(DateOpened, DateClosed)
as
(select TSK_START_DATE, BTK_CLOSED_DATE
FROM [PROC].ALL_AUDIT
WHERE
(BTK_CLOSED_DATE < #TheMonthLastDate OR
--TSK_START_DATE < #TheMonthLastDate
)
)
select * , #TheMonthLastDate TheMonthLastDate from yourTable

t-sql get all dates between 2 dates [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Getting Dates between a range of dates
Let's say I have 2 dates (date part only, no time) and I want to get all dates between these 2 dates inclusive and insert them in a table. Is there an easy way to do it with a SQL statement (i.e without looping)?
Ex:
Date1: 2010-12-01
Date2: 2010-12-04
Table should have following dates:
2010-12-01, 2010-12-02, 2010-12-03, 2010-12-04
Assuming SQL Server 2005+, use a recursive query:
WITH sample AS (
SELECT CAST('2010-12-01' AS DATETIME) AS dt
UNION ALL
SELECT DATEADD(dd, 1, dt)
FROM sample s
WHERE DATEADD(dd, 1, dt) <= CAST('2010-12-04' AS DATETIME))
SELECT *
FROM sample
Returns:
dt
---------
2010-12-01 00:00:00.000
2010-12-02 00:00:00.000
2010-12-03 00:00:00.000
2010-12-04 00:00:00.000
Use CAST/CONVERT to format as you like.
Using parameters for start & end:
INSERT INTO dbo.YOUR_TABLE
(datetime_column)
WITH sample AS (
SELECT #start_date AS dt
UNION ALL
SELECT DATEADD(dd, 1, dt)
FROM sample s
WHERE DATEADD(dd, 1, dt) <= #end_date)
SELECT s.dt
FROM sample s
You need a numbers table. If you don't have a permanent one this is a more efficient way of generating one than using a recursive CTE. A permanent one will be more efficient though as long as it is read from the buffer cache.
DECLARE #D1 DATE = '2010-12-01'
DECLARE #D2 DATE = '2010-12-04'
;WITH
L0 AS (SELECT 1 AS c UNION ALL SELECT 1),
L1 AS (SELECT 1 AS c FROM L0 A CROSS JOIN L0 B),
L2 AS (SELECT 1 AS c FROM L1 A CROSS JOIN L1 B),
L3 AS (SELECT 1 AS c FROM L2 A CROSS JOIN L2 B),
L4 AS (SELECT 1 AS c FROM L3 A CROSS JOIN L3 B),
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS i FROM L4)
SELECT DATEADD(day,i-1,#D1)
FROM Nums where i <= 1+DATEDIFF(day,#D1,#D2)
I just did something like this:
declare #dt datetime = '2010-12-01'
declare #dtEnd datetime = '2010-12-04'
WHILE (#dt < #dtEnd) BEGIN
insert into table(datefield)
values(#dt)
SET #dt = DATEADD(day, 1, #dt)
END
Repeated Question
Getting Dates between a range of dates
DECLARE #DateFrom smalldatetime, #DateTo smalldatetime;
SET #DateFrom='20000101';
SET #DateTo='20081231';
-------------------------------
WITH T(date)
AS
(
SELECT #DateFrom
UNION ALL
SELECT DateAdd(day,1,T.date) FROM T WHERE T.date < #DateTo
)
SELECT date FROM T OPTION (MAXRECURSION 32767);