将查询扩展到WHERE子句中指定的范围之外

时间:2009-03-13 18:01:26

标签: sql postgresql union

必须有更好的方法来编写此查询。

我想选择一对日期之间的所有数据。理想情况下,结果集的第一行和最后一行将是WHERE子句中指定的行。如果这些行不存在,我希望行在请求范围之前和之后。

一个例子:

如果我的数据是:

...
135321, 20090311 10:15:00
135321, 20090311 10:45:00
135321, 20090311 11:00:00
135321, 20090311 11:15:00
135321, 20090311 11:30:00
135321, 20090311 12:30:00
...

查询是:

    SELECT * 
    FROM data_bahf 
    WHERE param_id = 135321 
    AND datetime >= '20090311 10:30:00' 
    AND datetime <= '20090311 12:00:00'

我希望返回的数据包含10:15的行和12:30的行。不仅仅是严格符合WHERE子句的那些。

这是我提出的最好的。

SELECT * FROM (
    SELECT * 
    FROM data_bahf 
    WHERE param_id = 135321 
    AND datetime > '20090311 10:30:00' 
    AND datetime < '20090311 12:00:00'

    UNION

    (
        SELECT * FROM data_bahf 
        WHERE param_id = 135321 
        AND datetime <= '20090311 10:30:00' 
        ORDER BY datetime desc
        LIMIT 1
    )

    UNION

    (
        SELECT * FROM data_bahf 
        WHERE param_id = 135321 
        AND datetime >= '20090311 12:00:00'
        ORDER BY datetime asc
        LIMIT 1
    )
) 
AS A
ORDER BY datetime

(现在暂不使用SELECT *)

编辑: 我在param_id,datetime和(param_id,datetime)

上有索引

2 个答案:

答案 0 :(得分:3)

我会这样说:

SELECT 
  o.* 
FROM 
  data_bahf o
WHERE 
  o.param_id = 135321 
  AND o.datetime BETWEEN
  ISNULL(
    (
      SELECT   MAX(datetime) 
      FROM     data_bahf i
      WHERE    i.param_id = 135321 AND i.datetime <= '20090311 10:30:00'
    ),
    '0001-01-01 00:00:00'
  )
  AND
  ISNULL(
    (
      SELECT   MIN(datetime) 
      FROM     data_bahf i
      WHERE    i.param_id = 135321 AND i.datetime >= '20090311 12:00:00'
    ),
    '9999-12-31 23:59:59'
  )

编辑:后备补充。
如果没有与子查询匹配的行,则会生成NULL值,该值必须由ISNULL()捕获,否则BETWEEN运算符将失败,主查询将返回no完全没有行。

答案 1 :(得分:2)

首先,确保(param_id, datetime)

上有复合索引

其次,查询如下:

SELECT  *
FROM    data_bahf
WHERE   param_id = 135321
        AND datetime BETWEEN
        COALESCE(
        (
        SELECT  MAX(datetime)
        FROM    data_bahf
        WHERE   param_id = 135321
              AND datetime <= '2009-01-01 00:00:00'
        ), '0001-01-01')
        AND 
        COALESCE(
        (
        SELECT  MIN(datetime)
        FROM    data_bahf
        WHERE   param_id = 135321
              AND datetime >= '2009-01-02 00:00:00'
        ), '9999-01-01')

刚刚选中,它会在1.215 ms中运行200,000

的示例表