问题
I have a table with date ranges (seasons) for each year. The normal is that the end of the one season is the beggining of the next season. In the example below I have in bold the two irregular season setups. In the first the end of season 1 is a day after the beggining of season 2. In the second, the beggining of season 4 is one day after the end of seaon 3
+--------+----+--------------+--------------+
|SEASONID|YEAR|DATE FROM |DATE TO |
+--------+----+--------------+--------------+
|1 |14 | 2014-01-01 |**2014-01-31**|
|2 |14 |**2014-01-30**| 2014-03-01 |
|3 |14 | 2014-03-01 |**2014-05-22**|
|4 |14 |**2014-05-23**| 2014-10-16 |
|5 |14 | 2014-10-16 | 2014-12-01 |
+--------+----+--------------+--------------+
Is there a way to write a query that can capture the seasons that are not correctly setup? (the ones that the end of one season is not the beginning of the next)
回答1:
This answers half of your question: use the overlapping date queries from this article to find conflicting records:
-- 1.2) select date ranges that overlap [d1, d2) (d2 and end_date are exclusive)
-- SELECT * FROM <table> WHERE @d2 > start_date AND end_date > @d1
SELECT s1.*
FROM seasons AS s1
INNER JOIN seasons AS s2 ON s1.seasonid <> s2.seasonid
AND s2.date_to > s1.date_from
AND s1.date_to > s2.date_from
Result:
+--------+----+----------+----------+--------+----+----------+----------+
|seasonid|year|date_from |date_to |seasonid|year|date_from |date_to |
+--------+----+----------+----------+--------+----+----------+----------+
|1 |14 |2014-01-01|2014-01-31|2 |14 |2014-01-30|2014-03-01|
+--------+----+----------+----------+--------+----+----------+----------+
|2 |14 |2014-01-30|2014-03-01|1 |14 |2014-01-01|2014-01-31|
+--------+----+----------+----------+--------+----+----------+----------+
SQL Fiddle
回答2:
I hope this will help you
select * from stest st
join stest st1
on st.edate ! = st1.sdate
where st1.id = st.id + 1
where stest having the following detail
+--+----+----------+----------+
|id|year|sdate |edate |
+--+----+----------+----------+
|1 |14 |2014-01-01|2014-01-31|
+--+----+----------+----------+
|2 |14 |2014-01-30|2014-03-01|
+--+----+----------+----------+
|3 |14 |2014-03-01|2014-05-22|
+--+----+----------+----------+
|4 |14 |2014-05-23|2014-10-16|
+--+----+----------+----------+
|5 |14 |2014-10-16|2014-12-01|
+--+----+----------+----------+
and the above query will give the following result
+--+----+----------+----------+--+----+----------+----------+
|id|year|sdate |edate |id|year|sdate |edate |
+--+----+----------+----------+--+----+----------+----------+
|1 |14 |2014-01-01|2014-01-31|2 |14 |2014-01-30|2014-03-01|
+--+----+----------+----------+--+----+----------+----------+
|3 |14 |2014-03-01|2014-05-22|4 |14 |2014-05-23|2014-10-16|
+--+----+----------+----------+--+----+----------+----------+
from the result you can get id ( 1,2 ) and (3,4) are mismatched
and if you have do like below
select * from stest st
join stest st1
on st.edate = st1.sdate
where st1.id = st.id + 1
then you will get the matching result
+--+----+----------+----------+--+----+----------+----------+
|id|year|sdate |edateid |id|year|sdate |edate |
+--+----+----------+----------+--+----+----------+----------+
|2 |14 |2014-01-30|2014-03-01|3 |14 |2014-03-01|2014-05-22|
+--+----+----------+----------+--+----+----------+----------+
|4 |14 |2014-05-23|2014-10-16|5 |14 |2014-10-16|2014-12-01|
+--+----+----------+----------+--+----+----------+----------+
回答3:
An ad-hoc brute-force approach:
SELECT *
FROM seasons s1
CROSS JOIN seasons s2
WHERE NOT (s1.date_to <= s2.date_from OR s1.date_from >= s2.date_to);
Hopefully there are not enough records to cause performance issues with cartesian join. If you have SQL Server 2012 it can be improved using window functions (only compare adjacent seasons).
回答4:
DECLARE @T TABLE (
SeasonId INT NOT NULL,
Year INT NOT NULL,
DateFrom DATE NOT NULL,
DateTo DATE NOT NULL
)
INSERT @T VALUES (1, 14, '2014-01-01', '2014-01-31')
INSERT @T VALUES (2, 14, '2014-01-30', '2014-03-01')
INSERT @T VALUES (3, 14, '2014-03-01', '2014-05-22')
INSERT @T VALUES (4, 14, '2014-05-23', '2014-10-16')
INSERT @T VALUES (5, 14, '2014-10-16', '2014-12-01')
;WITH T AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY DateFrom) RowId
FROM @T
)
SELECT
A.SeasonId, A.DateTo,
B.SeasonId, B.DateFrom
FROM T A JOIN T B ON A.RowId + 1 = B.RowId
WHERE A.DateTo <> B.DateFrom
来源:https://stackoverflow.com/questions/21087348/sql-server-find-overlaping-date-ranges