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

发布于 2024-07-15 05:16:45 字数 1291 浏览 5 评论 0原文

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

我想选择一对日期之间的所有数据。 理想情况下,结果集的第一行和最后一行是 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) 的索引

There must be a better way of writing this query.

I want to select all the data between a pair of dates. Ideally the first and last rows of the result set would be those specifed in the WHERE clause. If those rows don't exist, I want the rows preceeding and following the requested range.

An example:

If my data is:

...
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
...

And the query is:

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

I want the returned data to include the row at 10:15, and that of 12:30. Not just those that strictly meet the WHERE clause.

This is the best I've come up with.

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

(Ignore the use of SELECT * for now)

EDIT:
I have indexes on param_id, datetime, and (param_id, datetime)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

感情洁癖 2024-07-22 05:16:45

我想说的是:

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 捕获该值> 运算符将失败,主查询将根本不返回任何行。

I'd say this:

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'
  )

EDIT: Fallback added.
When there is no row matching the sub-query, it will result in a NULL value, which must be caught by ISNULL() or the BETWEEN operator will fail and the main query will return no rows at all.

假装爱人 2024-07-22 05:16:45

首先,确保您在 (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 行的示例表

First, make sure that you have a composite index on (param_id, datetime)

Second, query like this:

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')

Just checked, it runs in 1.215 ms for a sample table of 200,000 rows

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文