MySQL:选择上面的行

时间:2016-06-04 21:41:46

标签: mysql sql

是否可以编写一个MySQL查询,从符合特定条件的那一行中选择一行中的所有项目?

例如,要获得“估值”的价格。大于5:

Date        Price   Valuation
01/06/2016    9.2       9
31/05/2016    9.3       5
27/05/2016    9.5       8
26/05/2016    9.7       7
25/05/2016    9.5       8
24/05/2016    9.3       4
23/05/2016    9.2       3
20/05/2016    9.2       5
19/05/2016    8.9       9
18/05/2016    9.1       4
17/05/2016    9.2       9

但是,在估值升至5以上之后,您将如何获得价格?

SynchronizationContext.Current

在这个例子中,它将是9.3,9.5,9.7,9.2和9.1

编辑:如果有帮助,可以将索引列添加到表中。

编辑"一天后"我的意思是表格中的下一行(而不是按时间顺序排列的第二天)

3 个答案:

答案 0 :(得分:1)

我们假设我们有

CREATE TABLE quotes( 
  `date` date not null primary key,
  price numeric(5,1) not null,
  valuation integer not null
);


INSERT INTO quotes VALUES
('2016-06-01', 9.2, 9),
('2016-05-31', 9.3, 5),
('2016-05-27', 9.5, 8),
('2016-05-26', 9.7, 7),
('2016-05-25', 9.5, 8),
('2016-05-24', 9.3, 4),
('2016-05-23', 9.2, 3),
('2016-05-20', 9.2, 5),
('2016-05-19', 8.9, 9),
('2016-05-18', 9.1, 4),
('2016-05-17', 9.2, 9);

然后,以下SELECT语句可以解决问题:

SELECT basedate, quotes.*
FROM 
(
    SELECT basedate, min(date) AS nextDate
    FROM
    (
        SELECT * FROM 
        (SELECT date as basedate FROM quotes WHERE Valuation > 5) as dates
        LEFT JOIN quotes ON dates.basedate < quotes.date
    ) as aggrtable
    GROUP BY basedate
) as fullTable
LEFT JOIN quotes ON fullTable.nextDate = quotes.date;

让我们从内到外检查这个:

  • innerst SELECT语句检索对所有VALUATION > 5感兴趣的引号。那些条件成立的日期在这里被称为basedate
  • 下一层对表本身进行非equi连接,确定所有可能的日期“在我们的基准日期之后。”
  • 别名aggrtable确定日期,这些日期在基准日期“之后”,但最接近基准日期(使用min聚合功能)。
  • 要最终再次从quotes检索值,结果将再次与原始表连接,使连接条件位于基准日期的“最小最近日期”。

注意:在大型表之间,这种非等式连接可能会变得丑陋:假设我们在数据库中有几十年的日期。在第二天,估值超过5.然后,这个非equi联接将生成结果中除前两个之外的所有日期。因此,如果您运气不好,这可能会导致O(n²)记录,这些记录需要暂时生成,然后通过min上的聚合再次压缩。因此,您的结果集最多只会有O(n)条记录,但可能需要O(n²)时间/空格。您也可以使用EXPLAIN语句对此讨论进行交叉检查;在那里你会发现一个EXTRA = "Using temporary, Using filesort",这在性能方面是非常邪恶的。

答案 1 :(得分:0)

如果只是想在估值高于五的任何日期之后立即找到日期/价格/估值,无论前几天的估值如何,都要使用:

select * from T
where Date in (
    select min(t2.Date)
    from T t1 inner join T t2 on t2.Date > t1.Date
    where t1.Valuation > 5
    group by t1.Date
)

解释:查找估值高于5的天数。在每个实例中,执行自联接以查找所有日期,并仅保留最早的日期。现在返回该日期列表的所有数据。如果你可以给它一个上限,就像从来不需要看一周以上那样,自联接会更快。

如果您正在寻找估值转换,那就更复杂了:

select * from T
where `Date` in (
    select t2.`Date`
    from T t1 inner join T t2
        on      t2.`Date` > t1.`Date`
            and t2.`Date` < date_add(t1.`Date`, interval 7 day) /* bound for performance */
    where
        /* valuation starts at or below 5 */
        t1.Valuation <= 5

        /* did we find the day after the next day? */
        and 3 = (
            select count(*) from T t3
            where t3.`Date` between t1.`Date` and t2.`Date`
        )

        /* did the valuation rise above 5 on the day in between */
        and 5 < (
            select t4.Valuation from T t4
            where t4.`Date` > t1.`Date` and t4.`Date` < t2.`Date`
        )
)

超越我首先相信你正在寻找从五岁以下到五岁以上的过渡。然后你想要那个之后的那天的价格。这种解释似乎与您的样本数据不匹配。

这是一个在SQL Server上测试查询的地方。 http://rextester.com/BQFJDE14701

答案 2 :(得分:0)

您基本上想要先前的估值。一种方法使用变量,另一种方法使用相关子查询:

select p.*,
      (select p2.valuation
       from prices p2
       where p2.date < p.date
       order by p2.date desc
       limit 1
      ) as prev_valuation
from prices p;

现在您只想添加先前估值的条件大于5. MySQL允许您使用having子句执行此操作:

select p.*,
      (select p2.valuation
       from prices p2
       where p2.date < p.date
       order by p2.date desc
       limit 1
      ) as prev_valuation
from prices p
having prev_valuation > 5;