2011-06-10 58 views
3

我有以下三个简单的T-SQL查询。第一个是一个范围边界(DATETIME型)中得到记录:在一系列边界内的SQL查询记录以及范围之外的最大/最小值

SELECT value, timestamp 
FROM myTable 
WHERE timestamp BETWEEN @startDT AND @endDT 

第二个是让最接近记录@startDT(DATETIME型)

SELECT TOP 1 
    value, timestamp 
FROM myTable 
WHERE timestamp > @startDT 
ORDER BY timestamp DESC 

,最后一个是@endDT后得到的最接近记录:

SELECT TOP 1 
    value, timestamp 
FROM myTable 
WHERE timestamp < @endDT 
ORDER BY timestamp ASC 

我想获得以上三个查询的所有记录的一组记录。我试图使用UNION,但似乎UNION中的子查询不允许ORDER BY子句。有没有有效的方法来获得我的结果?

. . * | * * * * * | * . . . 
     start  end 

上面的图表只显示了* s的记录作为我所需的记录,而| ... |是界限。

顺便说一下,myTable中的数据量是巨大的。我对UNION的理解并不是从UNION获取数据的有效方法。任何有效的方式来获取数据没有UNION?

+0

您确定使用'ORDER BY value,timestamp'从这些查询中获得了期望的结果吗?根据你的描述,我想你只想在时间戳上订购。否则,你会得到最接近边界的最小值。 – 2011-06-10 20:14:29

+0

你说得对,我只是通过时间戳来改变它。 – 2011-06-10 20:16:24

+0

很高兴看到这么多答案满足我的需求。 @Piotr Auguscik提到在性能方面,min/max比Order + top 1要好。是对的吗?根据答案,我找到了“最小/最大+分组依据”的解决方案。不知道哪一个更好。请记住myTable在我的情况下包含大量的记录。 – 2011-06-11 00:16:36

回答

3

如你所愿,没有UNION。

的MySQL(检测过

SELECT 
    dv1.timestamp, dv1.values 
FROM 
    myTable AS dv1 
WHERE 
    dv1.timestamp 
    BETWEEN (
      SELECT dv2.timestamp 
      FROM myTable AS dv2 
      WHERE dv2.timestamp < '@START_DATE' 
      ORDER BY dv2.timestamp DESC 
      LIMIT 1 
      ) 
    AND (SELECT dv3.timestamp 
      FROM myTable AS dv3 
      WHERE dv3.timestamp > '@END_DATE' 
      ORDER BY dv3.timestamp ASC 
      LIMIT 1 
     ) 

编辑对不起,我忘了通知一下T-SQL。

T-SQL(未测试

SELECT 
    dv1.timestamp, dv1.values 
FROM 
    myTable AS dv1 
WHERE 
    dv1.timestamp 
    BETWEEN (
      SELECT TOP 1 dv2.timestamp 
      FROM myTable AS dv2 
      WHERE dv2.timestamp > @START_DATE 
      ORDER BY dv2.timestamp DESC 
      ) 
    AND (SELECT TOP 1 dv3.timestamp 
      FROM myTable AS dv3 
      WHERE dv3.timestamp < @END_DATE 
      ORDER BY dv3.timestamp ASC 
     ) 

如果结果是不正确的,你可以只更换子查询(即运营商,以及ASC/DESC)。

跳出框框:)

+0

不错。我不是100%确定联合会是否效率较低。真的吗? – 2011-06-10 21:04:17

+1

顺便说一下,T-SQL不支持LIMIT 1。我认为它应该是TOP 1呢? – 2011-06-10 21:18:25

+0

有人说是的。事先,您可以使用'EXPLAIN the_query'来比较查询执行时间:)但是,在某些情况下,UNION似乎很有用,但我更愿意避免它。 – exodream 2011-06-10 21:23:15

0

您可以将这些有序查询放入子查询中以避免不能直接联合它们。有点烦人,但它会让你得到你想要的。

SELECT value, timestamp 
FROM myTable 
WHERE timestamp BETWEEN @startDT AND @endDT 
UNION 
SELECT value, timestamp 
FROM (
SELECT TOP 1 
    value, timestamp 
FROM myTable 
WHERE timestamp > @startDT 
ORDER BY value, timestamp DESC 
) x 
UNION 
SELECT value, timestamp 
FROM (
SELECT TOP 1 
    value, timestamp 
FROM myTable 
WHERE timestamp < @endDT 
ORDER BY value, timestamp ASC 
) x 
1

U可以使用最大/最小值来获得您需要的值。 Order by + top 1不是获得最大值的最佳方式,我可以在你的查询中看到。为了排序n个项目其O(n到2),获得最大应该只有O(n)

+0

然后我必须使用GROUP BY,如果我使用max/min。我的查询是简化的。实际上,记录中有两个以上的字段,例如value1,value2,...,timestamp。 – 2011-06-10 20:29:48

1
SELECT value, timestamp 
FROM myTable 
WHERE timestamp BETWEEN @startDT AND @endDT 
union 
select A.Value, A.TimeStamp 
From (
SELECT TOP 1 
    value, timestamp 
FROM myTable 
WHERE timestamp > @startDT 
ORDER BY value, timestamp DESC) A 
Union 
Select A.Value, A.TimeStamp 
From (
SELECT TOP 1 
    value, timestamp 
FROM myTable 
WHERE timestamp < @endDT 
ORDER BY value, timestamp ASC) A 
1

的在您的文章的第二个和第三个查询没有太大的意义,因为

WHERE timestamp > @startDT 

WHERE timestamp < @endDT 

结果时间戳INSIDE的范围,但您的描述

. . * | * * * * * | * . . . 
     start  end 

上面的图表只显示* s的记录作为我所需的记录,而| ... |是界限。

意味着不同的东西。

所以下面的说明,并使用下面的映射

myTable = Posts 
value = score 
timestamp = creationdate 

我写了一篇关于data.stackexchange.com this query(从exodream的答案,但与比较运营商在 正确 相反的方向修改)

DECLARE @START_DATE datetime 
DECLARE @END_DATE datetime 
SET @START_DATE = '2010-10-20' 
SET @END_DATE = '2010-11-01' 

SELECT score, 
     creationdate 
FROM posts 
WHERE creationdate BETWEEN (SELECT TOP 1 creationdate 
          FROM posts 
          WHERE creationdate < @START_DATE 
          ORDER BY creationdate DESC) 
          AND 
            (SELECT TOP 1 creationdate 
            FROM posts 
            WHERE creationdate > @END_DATE 
            ORDER BY creationdate ASC) 
ORDER by creationDate 

,输出

score creationdate   
----- ------------------- 
4  2010-10-19 23:55:48 
3  2010-10-20 2:24:50 
6  2010-10-20 2:55:54 
... 
... 
7  2010-10-31 23:14:48 
4  2010-10-31 23:18:17 
4  2010-10-31 23:18:48 
0  2010-11-01 3:59:38 

(382 row(s) affected) 

请注意第一行和最后一行如何超出范围限制

相关问题