SQLite以前在where子句中选择值

时间:2012-07-13 21:44:42

标签: sql excel sqlite odbc

序言(你可以跳过这个,这只是我的理由)

我创建了一个使用sqlite作为其数据库后端的应用程序,并且该模式在一般应用程序使用期间非常有效(并且执行)。

现在我正在尝试为它构建一个报告系统,我已经构建了一个excel xll,它可以从一个未命名的DSN创建查询表。因此,我必须在sql中完成所有报告(即,我无法以编程方式执行任何操作)。这对于除一个查询之外的所有内容都非常有效...

///跳过这里....

我的数据库包含一系列功能,这些功能具有id,距离以及该功能是否为标记的指示符。 id不一定与距离的顺序相同(id为10的要素可能具有距离100,而具有id 11的要素可能具有距离90)。

因此该项目基本上如下:

Feature { int id, int distance, bool is_marker }

我要做的是找到也是标记的下一个和上一个功能。

///编辑

我的第一次尝试使用:

select 
*          /* I want all the data from this feature */
(select MAX(f2.distance) - f1.distance 
    from feature as f2
    where f2.is_marker && f2.distance < f1.distance) /* and the distance to the previous marker */
from feature as f2

第二次尝试(这个有效,只需要WAAAY太长时间就可以获得100,000个功能,大约9天......):

select
*,          /* I want all the data from this feature */
(select f1.distance - MAX(f2.distance)
    from feature as f2
    where f2.distance AND f2.distance< f1.distance) /* and the distance to the previous marker */
from feature as f1

此查询确实返回了我想要的内容,并且对小型数据库执行了充分的操作,但我也必须支持更大的数据库。

(有些数据库的功能少于1000个,但我现在正在处理的功能有> 90,000个功能。对1000个功能的查询需要&lt; 1s,但90,000个功能的查询需要20个小时。是因为它没有线性增长导致性能下降80倍:20 * 60 * 60 /(90,000 / 1000)= 8000)

后端数据库使用sqlite,我使用sqliteodbc连接器连接excel。

如果我要在代码中执行此操作,我会这样做:

var features = featureRepository.GetAll();
var featuresWithMarkerDistance = new List<FeatureWithMarkerDistance>();
var previousMarker = null;
for(var index = 0; index < features.Length; index++) {
    var currentFeature = features[index];
    featuresWithMarkerDistance.Add(
        new FeaturesWithMarkerDistance(currentFeature, 
            feature.distance - previousMarker.distance));
    if(feature.is_marker) {
        previousMarker = feature;
    }
}

// FeatureWithMarkerDistance { int id, int distance, bool is_marker, int marker_distance }

//编辑:

这是一个具体的例子:

(The underlying table)
feature_id is_marker distance
1          false     100
2          false     90
3          false     101
4          true      50
5          false     5
6          true      85
7          false     150
8          false     75

(距离指数)

我想要的结果:

feature_id is_marker distance distance_to_closest_previous_marker
1          false     100      15
2          false     90       5
3          false     101      16
4          true      50       null
5          false     5        null
6          true      85       35
7          false     150      65
8          false     75       25

因此,如果我获得feature_id 1的前一个标记,则feature_id 1的距离为100,距离85最近的标记为feature_id 6.要获得距离最近的前一个标记的距离,我需要(100 - 85) = 15.我需要为报告中包含的每个功能获取此值。 (这必须在单个sql查询中完成,因为我正在使用带excel的odbc连接器)。上面的查询确实获取了我想要的东西,它只是执行得非常糟糕,因为在where子句中它必须在整个数据库中搜索每个特征。

我想做的是:(除非有更高效的方式)

   select *          
    /* I want all the data from this feature */ 
    /* previous  = */ (select MAX(f2.distance) - f1.distance 
        from feature as f2
        where f2.is_marker && f2.distance >= previous && f2.distance < f1.distance) 
    /* and the distance to the previous marker */
    from feature as f2

所以基本理论是我会存储前一个标记值,只有在我寻找下一个标记时才会查看该值。

对于最初的混淆感到抱歉(我忘记了原来的MAX())

3 个答案:

答案 0 :(得分:0)

不知道SQLite,但做了类似的工作(我查找语法,找到LEFT JOIN和EXISTS,但不是不存在)?

select f2.*, f2.distance - f1.distance
from feature f2
left join feature f1 on f1.is_marker
                    and f2.distance > f1.distance
                    and not exists(select 1 from feature f1b
                                   where f1b.is_marker
                                     and f2.distance > f1b.distance
                                     and f1.distance < f1b.distance)
where f2.is_marker

我对性能没有任何线索,但是期望(is_marker,distance)上的索引可能是有利的(你必须测试是否在索引中包含is_marker是否有用,除此之外取决于SQLite,它可能还取决于具有is_marker = true的列的百分比。

答案 1 :(得分:0)

这些例子确实有帮助。你走了。

SELECT F2.feature_id, F2.is_marker, F2.distance, 
       F2.distance - (SELECT F1.distance FROM features F1
                      WHERE F1.is_marker<>0 
                        AND F1.distance<F2.distance
                      ORDER BY F1.distance DESC
                      LIMIT 1) AS "distance_to_closest_previous_marker"
FROM features F2

答案 2 :(得分:0)

我使用了SQLite3 shell,我尝试了你的查询改编

SELECT *, 
       (SELECT MIN(feature.distance-distance) FROM feature AS f
               WHERE is_marker AND distance<feature.distance) 
       FROM feature;

它在5000条记录中表现相当不错。也许你最薄弱的地方是sqliteobdc? 如果确实它仍然很慢,并且假设你的is_marker很少,那么你可以创建一个只有距离feature_marker为真的特征的表:

CREATE TEMP TABLE markers_distance (distance);
CREATE UNIQUE INDEX markers_idx ON markers_distance (distance);
INSERT OR IGNORE INTO markers_distance 
       SELECT distance FROM feature WHERE is_marker;

现在您对markers_distance的查询应该更快:

SELECT *, 
       (SELECT MIN(feature.distance-distance) FROM markers_distance
               WHERE distance<feature.distance) 
       FROM feature;