我有一张桌子:
表:
START END
1 Jan 09 31 Jan 2009
1 Feb 09 28 Feb 2009
1 Mar 09 31 Mar 2009
1 Apr 09 01 May 2009
1 May 09 31 May 2009
1 Jun 09 01 Jul 2009
1 Jul 09 31 Jul 2009
1 Aug 09 31 Aug 2009
1 Sep 09 01 Oct 2009
1 Oct 09 31 Oct 2009
1 Nov 09 01 DEC 2009
1 DEC 09 31 DEC 2009
1 Jan 10 31 Jan 2010
1 Feb 10 03 Mar 2010
1 Mar 10 31 Mar 2010
1 Apr 10 01 May 2010
1 May 10 31 May 2010
1 Jun 10 01 Jul 2010
1 Jul 10 31 Jul 2010
1 Aug 10 31 Aug 2010
1 Sep 10 01 Oct 2010
1 Oct 10 31 Oct 2010
1 Nov 10 01 DEC 2010
1 DEC 10 31 DEC 2010
1 Jan 09 31 Mar 2009
1 Apr 09 30 Jun 2009
1 Jul 09 01 Oct 2009
1 Oct 09 31 DEC 2009
1 Jan 10 31 Mar 2010
1 Apr 10 30 Jun 2010
1 Jul 10 01 Oct 2010
1 Oct 10 31 DEC 2010
1 Jan 09 31 DEC 2009
1 Jan 10 31 DEC 2010
以上包含2009年,2010年的每个月,每个季度和每年。
我有另一个带有以下内容的表:
表2
START END
15-12-09 31-12-09
15-01-12 31-12-13
01-01-11 31-12-13
30-01-98 31-12-13
01-01-98 31-12-13
01-01-98 31-12-13
23-12-12 31-12-13
12-11-11 31-12-13
01-01-10 31-12-13
对于表2中的每个条目,我需要找到它可能落入表1中的时间范围。
对于前。 从表2,第一个条目开始-
15-12-09 31-12-09
属于:
1 DEC 09 31 DEC 2009
1 Oct 09 31 DEC 2009
1 Jan 09 31 DEC 2009
在Oracle SQL中是否可以识别它?
如果可能的话,您可以提供插入脚本吗?
返回一个表中的结束日期在另一表中的开始日期之后或等于开始日期,并且该表中的开始日期在另一表的结束日期之前或之后的记录。
Marmite Bombers的答案为这两种情况都提供了正确的答案...
您必须先定义table1间隔下降的含义
一般有两种可能的解释。 SUBINTERVAL比较严格,
即匹配间隔完全被参考间隔覆盖。
MATCH
reference
另一种更为宽松的可能性是"相交",这意味着两个间隔至少有一个共同点。
MATCH
reference
根据该决定,您使用不同的联接条件。
在下面第一种可能性的查询中,只需交换注释即可获得另一个选项。
请注意,下面将创建带有模拟数据的表。
SELECT
tab2.start_d match_start, tab2.end_d match_end,
tab.start_d ref_start, tab.end_d ref_end
FROM tab2
JOIN tab
-- option SUBINTERVAL
ON tab.start_d <= tab2.start_d AND tab2.end_d <= tab.end_d
-- option INTERSEC
-- on NOT (tab2.end_d < tab.start_d OR tab2.start_d > tab.end_d)
ORDER BY 1,2,3;
SUBINTERVAL选项的结果
MATCH_START MATCH_END REF_START REF_END
----------------- ----------------- ----------------- -----------------
15.12.09 00:00:00 31.12.09 00:00:00 01.01.09 00:00:00 31.12.09 00:00:00
15.12.09 00:00:00 31.12.09 00:00:00 01.10.09 00:00:00 31.12.09 00:00:00
15.12.09 00:00:00 31.12.09 00:00:00 01.12.09 00:00:00 31.12.09 00:00:00
您将获得更多关于INTERSECT选项的记录。
这是测试数据
CREATE TABLE tab AS
WITH tab AS (
-- reference intervals
-- months
SELECT add_months(to_date('01012009','ddmmyyyy'),rownum-1) start_d,
add_months(to_date('01012009','ddmmyyyy'),rownum)-1 end_d FROM dual CONNECT BY level <=24
UNION ALL
-- quartals
SELECT add_months(to_date('01012009','ddmmyyyy'),3*(rownum-1)) start_d,
add_months(to_date('01012009','ddmmyyyy'),3*rownum)-1 end_d FROM dual CONNECT BY level <=24/3
UNION ALL
-- years
SELECT add_months(to_date('01012009','ddmmyyyy'),12*(rownum-1)) start_d,
add_months(to_date('01012009','ddmmyyyy'),12*rownum)-1 end_d FROM dual CONNECT BY level <=24/12
)
SELECT * FROM tab;
CREATE TABLE tab2 AS
WITH tab2 AS (
-- matched intervals
SELECT to_date('15-12-09','dd-mm-rr') start_d, to_date('31-12-09','dd-mm-rr') end_d FROM dual UNION ALL
SELECT to_date('15-01-12','dd-mm-rr') start_d, to_date('31-12-13','dd-mm-rr') end_d FROM dual UNION ALL
SELECT to_date('15-01-98','dd-mm-rr') start_d, to_date('31-12-13','dd-mm-rr') end_d FROM dual
)
SELECT * FROM tab2;
如果我在tab2中将15-01-12更改为15-01-98,它将失败。
@当什么失败? tab的任何间隔都不包括15-01-98到31-12-13的间隔,那里的查询在START和END列中返回NULL。 我将此新行添加到tab2
如果我更改从双TO中选择to_date(15-01-12,dd-mm-rr)start_d,to_date(31-12-13,dd-mm-rr)end_d选择to_date(15-01-98,dd-mm -rr)start_d,to_date(31-12-13,dd-mm-rr)end_d来自对偶,它为我提供了NULL
@dang-您期望获得什么其他价值? 对于表2中的每个条目,我需要找到它可能落在表1中的时间范围。您是说它与表1相交吗? 即 在这种情况下,来自table1的所有记录?
最终查询是什么?
简单之间应该有所帮助。
使用两个之间的语句首先检查table1的时间范围内是否为table2的start_date,第二个之间的语句将检查table1的相同时间范围内是否也为table2的end_date。两项检查应同时进行,因此应在它们之间使用和。
此外,成为包含在内的"之间"的工作方式如下:对于第一个参数
它检查>或=以及第二个参数
因此,以下语句等于:
t2.start_date BETWEEN t1.start_date AND t1.end_date
和
t2.start_date >= t1.start_date AND t2.start_date <= t1.end_date
您要查找的SQL将如下所示:
SELECT t2.*, '->', t1.* FROM table2 t2,
table1 t1
WHERE t2.start_date BETWEEN t1.start_date AND t1.end_date
AND t2.end_date BETWEEN t1.start_date AND t1.end_date
我没有很出色的表现就选择了不是很简单的方法=)
WITH days (dt, max_dt) AS
(SELECT (SELECT MIN(start_dt) FROM table2) AS dt
,(SELECT MAX(end_dt) FROM table2) AS max_dt
FROM dual
UNION ALL
SELECT dt+1 AS dt
,max_dt AS max_dt
FROM days
WHERE dt
)
SELECT DISTINCT
t2.start_dt AS start_dt2
,t2.end_dt AS end_dt2
,t.start_dt AS start_dt
,t.end_dt AS end_dt
FROM table2 t2
JOIN days d ON (t2.start_dt <=d.dt AND t2.end_dt >= d.dt)
JOIN TABLE t ON (t.start_dt <=d.dt AND t.end_dt >= d.dt)
我尝试介绍以下情况:
TABLE INTERVAL |---------|
table2 INTERVAL |---------------|
table2 INTERVAL |----|
table2 INTERVAL |--------|
table2 INTERVAL |-----|
在SQL中,表达间隔的最佳方式是:
SELECT *
FROM table2
JOIN table1
ON
table1.start BETWEEN table2.start AND table2.end
OR
table2.start BETWEEN table1.start AND table1.end;
每个相交的情况都属于这两种情况之一。
首先,如果您将所有内容都以标准DATE格式存储,那么生活将变得非常简单,这样您就无需在查询中进行转换。那么模式就是:
WHERE table2.start <= table1.end
AND table1.start <= table2.end
我真的不了解您的意思以及您想在这里实现的目标,但是我希望这会对您有所帮助。不知何故,我能够(部分地)获得您所引用的输出。只需对此代码进行一些调整即可。
SELECT CONVERT(VARCHAR(25),CONVERT(DATE,tbl1.START)) 'start',
CONVERT(VARCHAR(25),CONVERT(DATE,tbl1.[END])) 'end',
CONVERT(VARCHAR(25),CONVERT(DATE,tbl2.START)) + ' - ' + CONVERT(VARCHAR(25),CONVERT(DATE,tbl2.[END])) 'table2'
从tbl1,tbl2
其中(CONVERT(DATE,tbl2.START)> = CONVERT(DATE,tbl1.START))和
(CONVERT(DATE,tbl1。[END])<= CONVERT(DATE,tbl1。[END]))
嗯 这似乎不像Oracle语法。 您认为CONVERT()函数有什么作用?