我有两个表,我试图根据两个标准加入。其中一个标准是来自t1的日期介于t2中的日期和t2中的下一个日期之间。另一个是来自t1的名称与来自t2的名称匹配。
即。如果t2看起来像这样:
Record Name Date
1 A1234 2016-01-03 04:58:00
2 A1234 2015-12-15 08:34:00
3 A5678 2016-01-04 03:14:00
4 A1234 2016-01-05 21:06:00
然后:
2016-01-03 04:58:00
和2016-01-05 21:06:00
之间的任何记录都会加入到记录1中。2015-12-15 08:34:00
和2016-01-03 04:58:00
之间的任何记录都将加入记录2 我最初的方法是使用相关子查询来查找下一个日期。但是,由于记录数量很多,我确定这将花费一年多的时间来执行,因为它会在每次迭代期间搜索t2的所有下一个日期。原SQLite:
CREATE TABLE outputtable AS SELECT * FROM t1, t2 d
WHERE t1.Name = d.Name AND t1.Date BETWEEN d.Date AND (
SELECT * FROM (
SELECT Date from t2
WHERE t2.Name = d.Name
ORDER BY Date ASC )
WHERE Date > d.Date
LIMIT 1 )
现在,我想为t2中的所有记录找到下一个日期,并在t2中创建一个包含下一个日期的新列。这样,我只搜索下一个约400,000次而不是560亿次,大大提高了我的表现。
因此,我查找的查询的输出将使t2看起来像这样:
Record Name Date Next_Date
1 A1234 2016-01-03 04:58:00 2016-01-05 21:06:00
2 A1234 2015-12-15 08:34:00 2016-01-03 04:58:00
3 A5678 2016-01-04 03:14:00 2999-12-31 23:59:59
4 A1234 2016-01-05 21:06:00 2999-12-31 23:59:59
然后,我可以简单地查询t1.Date
是否在t2.Date
和t2.Next_Date
之间。
如何构建一个查询,将下一个日期添加到t2中的新列?
答案 0 :(得分:0)
您应该只使用下面的查询来加入表格,而不是添加新列:
SELECT
T1.*,
T2_1.*
FROM
T1
INNER JOIN T2 T2_1 ON
T2_1.Name = T1.Name AND
T2_1.some_date < T1.some_date
LEFT OUTER JOIN T2 T2_2 ON
T2_2.Name = T1.Name AND
T2_2.some_date > T2_1.some_date
LEFT OUTER JOIN T2 T2_3 ON
T2_3.Name = T1.Name AND
T2_3.some_date > T2_1.some_date AND
T2_3.some_date < T2_2.some_date
WHERE
T2_3.Name IS NULL
您可以使用NOT EXISTS执行相同操作,但此方法通常具有更好的性能。
答案 1 :(得分:0)
您可以使用适当的索引加速(子)查询。 要检查实际使用的索引,请使用Odata Controller: How to convert Odata response to C# object at client。
您的原始查询,没有任何索引,将由SQLite 3.10.0执行,如下所示:
0|0|0|SCAN TABLE t1 0|1|1|SEARCH TABLE t2 AS d USING AUTOMATIC COVERING INDEX (name=?) 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 1 1|0|0|SCAN TABLE t2 1|0|0|USE TEMP B-TREE FOR ORDER BY
(“自动”索引仅为此查询临时创建;优化程序估计这仍然比不使用任何索引更快。)
在这种情况下,您可以通过索引用于查找的所有列来获得最佳查询计划:
create index i1nd on t1(name, date);
create index i2nd on t2(name, date);
0|0|1|SCAN TABLE t2 AS d 0|1|0|SEARCH TABLE t1 USING INDEX i1nd (name=? AND date>? AND date<?) 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 1 1|0|0|SEARCH TABLE t2 USING COVERING INDEX i2nd (name=? AND date>?)
答案 2 :(得分:-1)
我已经在大约1 mil行的表上使用了这种方法并且成功了。显然,创建一个覆盖此查询的索引将有助于提高性能。
此方法使用#[derive(Copy, Clone)]
struct AngleUnit;
struct Point {
x: f32,
y: f32,
z: f32,
unit: AngleUnit,
}
fn factor(from: AngleUnit, to: AngleUnit) -> f32 {
1f32
}
impl Point {
pub fn new(x: f32, y: f32, z: f32, unit: AngleUnit) -> Point {
Point { x, y, z, unit }
}
fn scale(&mut self, factor: f32) {
self.x *= factor;
self.y *= factor;
self.z *= factor;
}
fn convert(&mut self, unit: AngleUnit) {
let point_unit = self.unit;
self.scale(factor(point_unit, unit));
}
}
fn main() {}
创建要加入的值。在CTE中创建RANK
后(出于可读性原因使用此方法,请更正样式或个人偏好),使用子查询将rnk连接到rnk + 1;又名下一个日期。
以下是使用示例值代码的示例。
RANK
编辑:在下面添加了代码输出。
上面的代码产生以下输出。
IF OBJECT_ID('tempdb..#T2') IS NOT NULL
DROP TABLE #T2
CREATE TABLE #T2
(
Record INT NOT NULL PRIMARY KEY,
Name VARCHAR(10),
[DATE] DATETIME,
)
INSERT INTO #T2
VALUES (1, 'A1234', '2016-01-03 04:58:00'),
(2, 'A1234', '2015-12-15 08:34:00'),
(3, 'A5678', '2016-01-04 03:14:00'),
(4, 'A1234', '2016-01-05 21:06:00');
WITH Rank_Dates
AS (Select *
,rank() OVER(PARTITION BY #t2.name ORDER BY #t2.date DESC) AS rnk
FROM #T2)
select RD1.Record,
RD1.Name,
RD1.DATE,
COALESCE (RD2.DATE, '2999-12-31 23:59:59') AS NEXT_DATE
FROM Rank_Dates RD1
LEFT JOIN Rank_Dates RD2
ON RD1.rnk = RD2.rnk + 1
AND RD1.Name = RD2.Name
ORDER BY RD1.Record -- ORDER BY is optional
;
随机说明。使用Record Name DATE NEXT_DATE
1 A1234 2016-01-03 04:58:00.000 2016-01-05 21:06:00.000
2 A1234 2015-12-15 08:34:00.000 2016-01-03 04:58:00.000
3 A5678 2016-01-04 03:14:00.000 2999-12-31 23:59:59.000
4 A1234 2016-01-05 21:06:00.000 2999-12-31 23:59:59.000
代替硬编码CURRENT_TIMESTAMP
会产生类似的结果吗?