我有一张名为" mytable"的表格。列是
Time_Stamp (datetime) PK
Time_stamp_ms (int) PK
data1 (int)
data2 (int)
data3 (int)
data4 (int)
data5 (int)
data6 (int)
cycle (int)
name (varstring)
我想通过Time_Stamp和Time_stamp_ms(我知道如何从另一个问题执行此操作)进行排序,然后每个时间周期达到1,我想从上一行获取Time_Stamp和Time_Stamp_ms。周期是1,2,3,4 ...... n表示它总是递增1。
这张表可能会有数百万行。
也没有PHP。
我的桌子有一个样本:
Time_Stamp Time_Stamp_ms d1 d2 d3 d4 d5 d6 cycle name
2014-04-24 09:09:37 765 5555 4444 3333 2222 1111 123 1 name
2014-04-24 09:09:37 845 5555 4444 3333 2222 1111 123 2 name
2014-04-24 09:09:37 925 5555 4444 3333 2222 1111 123 3 name
2014-04-24 09:09:38 5 5555 4444 3333 2222 1111 123 4 name
2014-04-24 09:09:38 85 5555 4444 3333 2222 1111 123 5 name
2014-04-24 09:09:38 165 5555 4444 3333 2222 1111 123 6 name
2014-04-24 09:09:38 245 5555 4444 3333 2222 1111 123 7 name
2014-04-24 09:09:38 325 5555 4444 3333 2222 1111 123 8 name
2014-04-24 09:09:38 405 5555 4444 3333 2222 1111 123 9 name
2014-04-24 09:09:38 485 5555 4444 3333 2222 1111 123 10 name
2014-04-24 09:09:38 565 5555 4444 3333 2222 1111 123 11 name
2014-04-24 09:09:38 645 5555 4444 3333 2222 1111 123 12 name
2014-04-24 09:09:38 725 5555 4444 3333 2222 1111 123 13 name
2014-04-24 09:09:38 805 5555 4444 3333 2222 1111 123 1 name
2014-04-24 09:09:38 885 5555 4444 3333 2222 1111 123 2 name
2014-04-24 09:09:38 965 5555 4444 3333 2222 1111 123 3 name
2014-04-24 09:09:39 45 5555 4444 3333 2222 1111 123 4 name
2014-04-24 09:09:39 125 5555 4444 3333 2222 1111 123 5 name
2014-04-24 09:09:39 205 5555 4444 3333 2222 1111 123 6 name
2014-04-24 09:09:39 285 5555 4444 3333 2222 1111 123 1 name
2014-04-24 09:09:39 365 5555 4444 3333 2222 1111 123 2 name
2014-04-24 09:09:39 445 5555 4444 3333 2222 1111 123 3 name
2014-04-24 09:09:39 525 5555 4444 3333 2222 1111 123 4 name
2014-04-24 09:09:39 605 5555 4444 3333 2222 1111 123 5 name
2014-04-24 09:09:39 685 5555 4444 3333 2222 1111 123 6 name
2014-04-24 09:09:39 765 5555 4444 3333 2222 1111 123 1 name
2014-04-24 09:09:39 845 5555 4444 3333 2222 1111 123 2 name
2014-04-24 09:09:39 925 5555 4444 3333 2222 1111 123 3 name
应该回复我:
Time_Stamp Time_Stamp_ms d1 d2 d3 d4 d5 d6 cycle name
2014-04-24 09:09:38 725 5555 4444 3333 2222 1111 123 13 name
2014-04-24 09:09:39 205 5555 4444 3333 2222 1111 123 6 name
2014-04-24 09:09:39 685 5555 4444 3333 2222 1111 123 6 name
答案 0 :(得分:4)
如评论中所述,您确实需要一个指示行顺序的字段。 pkey int primary key auto_increment
字段不保证最新的行始终具有最大的id,因此严格来说,100%的时间不起作用。包含精确插入时间的列可以。
假设(我知道错误),您的值字段是可以排序的字段,此查询将获取id = 1之前的每一行。要获得正确的结果,请创建一个有序的字段,并将value
替换为两个order by
子句中的该字段
更新了查询:http://sqlfiddle.com/#!2/9cf7d1/1/0
SELECT Time_Stamp, Time_stamp_ms, cycle FROM (
SELECT
COALESCE((@preVal=1), 0) AS afterOne,
m.*,
@preVal:=m.cycle
FROM mytable as m,
(SELECT @preVal:=NULL) AS d
ORDER BY Time_Stamp desc, Time_stamp_ms desc
) t
WHERE afterOne = 1
ORDER BY Time_Stamp, Time_stamp_ms;
另外一个注意事项。如果您正在处理大数据集,则可以通过将内部查询插入临时表,索引afterOne,然后选择最终结果来发现性能大幅提升。 MySQL因为subquerys的速度慢而臭名昭着。
PS。嗯,我现在看到我可能选择了不好,之后真的意味着在命令提升之前。哦,无论如何,它的占位符可以命名为任何有意义的东西。
答案 1 :(得分:3)
正如mcalex所说
您没有主键。 2.数据的行顺序应该无关紧要。如果您希望订购这些行,则需要一个字段来帮助完成此操作。那么,你可以在某一行之前要求排
试试这个
SELECT * from
(
Select @prev As previous,@pid as `Previous id`,@pid := e.id As `id` ,@prev := e.value As current
From
(
Select @prev := null,@pid := 0
) As i,tbl As e
) x
Where id=1 And Previous is not null;
<强> Fiddle Demo 强>
<强>输出强>
+---------------------------------------------------+
| PREVIOUS | PREVIOUS_ID | Current_ID | CURRENT |
+---------------------------------------------------+
| C | 3 | 1 | D |
| F | 3 | 1 | G |
| X | 4 | 1 | J |
+---------------------------------------------------+
答案 2 :(得分:1)
我的第一选择可能是使用上述建议之一生成序列号。然而,有大量记录构建一个类似的序列可能会很慢(特别是如果你忽略了更多的记录)。
然而,另一种选择是进行连接。这很麻烦,因为你有2列来确定哪一个是前一条记录。
没有经过测试但是这样的事情: -
SELECT a.*, b.Time_Stamp, b.Time_stamp_ms
FROM
(
SELECT a.Time_Stamp, a.Time_stamp_ms, a.cycle, MAX(DATE_ADD(b.Time_Stamp, INTERVAL b.Time_stamp_ms MICROSECONDS)) AS latest_prev_record
FROM mytable a
INNER JOIN mytable b
ON DATE_ADD(a.Time_Stamp, INTERVAL a.Time_stamp_ms MICROSECONDS) > DATE_ADD(b.Time_Stamp, INTERVAL b.Time_stamp_ms MICROSECONDS)
WHERE a.cycle = 1
GROUP BY a.Time_Stamp, a.Time_stamp_ms, a.cycle
) Sub1
INNER JOIN mytable a
ON a.Time_Stamp = Sub1.Time_Stamp,
AND a.Time_stamp_ms = Sub1.Time_stamp_ms,
AND a.cycle = Sub1.cycle
INNER JOIN mytable b
ON DATE_ADD(b.Time_Stamp, INTERVAL b.Time_stamp_ms MICROSECONDS) = Sub1.latest_prev_record
如果您只想要时间戳而没有其他数据,并且如果您有一个组合的日期/时间/毫秒字段(那么您可以使用子查询),这可以变得非常简单。如果你只是拥有一个连续的id字段的所有记录(即,按顺序排列),那就更容易了。
编辑 - 如果您只希望在第1周期之前返回最后一条记录,则简化: -
SELECT z.*
FROM
(
SELECT a.Time_Stamp, a.Time_stamp_ms, MAX(DATE_ADD(b.Time_Stamp, INTERVAL b.Time_stamp_ms MICROSECOND)) AS latest_prev_record
FROM mytable a
INNER JOIN mytable b
ON DATE_ADD(a.Time_Stamp, INTERVAL a.Time_stamp_ms MICROSECOND) > DATE_ADD(b.Time_Stamp, INTERVAL b.Time_stamp_ms MICROSECOND)
WHERE a.cycle = 1
GROUP BY a.Time_Stamp, a.Time_stamp_ms
) Sub1
INNER JOIN mytable z
ON DATE_ADD(z.Time_Stamp, INTERVAL z.Time_stamp_ms MICROSECOND) = Sub1.latest_prev_record
再次编辑。
您可以为组合时间戳添加一个十进制字段(为其添加索引)并填充: -
update `mytable` set `timestamp_full` = UNIX_TIMESTAMP(`Time_Stamp`) + (`Time_stamp_ms` / 1000)
然后您可以使用以下SQL来获取所需的记录: -
SELECT z.*
FROM
(
SELECT a.timestamp_full, MAX(b.timestamp_full) AS latest_prev_record
FROM mytable a
INNER JOIN mytable b
ON a.timestamp_full > b.timestamp_full
WHERE a.cycle = 1
GROUP BY a.timestamp_full
) Sub1
INNER JOIN mytable z
ON z.timestamp_full = Sub1.latest_prev_record
答案 3 :(得分:0)
如果它只是一个你正在使用的小表(在10.000行以下),我认为最好的解决方案是获取整个事物并“手动”选择行(=在PHP循环中)。它肯定会比任何基于SQL的解决方案快得多,因为您只需要获取ID和主键来选择结果行。
说到一个严格的基于SQL的解决方案,你需要一个存储过程和一个游标来沿着结果集步进(这允许你退一步) - 但它不是非常有效,因为你需要查询整个表和逐个进行匹配。 基于索引的查询无法执行此操作,因此您获得的任何SQL解决方案都将沿着整个表格进行(执行“完全扫描”),因此不会很快。
AND YES,之前的答案是正确的,因为行的顺序无关紧要。它们有点“随机”,或者至少你应该像对待它们一样看待它们。 (即使您执行ALTER TABLE ... ORDER BY,也无法确定在修改单行的下一个操作之后。)
答案 4 :(得分:0)
作为另一个答案发布,因为它变得越来越复杂,这更像是一个额外选项的讨论。
如果有一个索引列来检查最新记录,或者检查最新的一组循环,那么进行连接会更容易。
如果为循环编号添加一列,则最初可以使用以下内容填充: -
SET @cycle_no = 0;
UPDATE mytable
SET cycle_no=@cycle_no:=@cycle_no + 1
WHERE cycle = 1
ORDER BY time_stamp, time_stamp_ms;
然后
UPDATE mytable a
SET a.cycle_no = (SELECT MAX(b.cycle_no) FROM mytable b WHERE a.time_stamp < b.time_stamp OR (a.time_stamp a.time_stamp < b.time_stamp b.time_stamp AND a.time_stamp_ms < b.time_stamp_ms ))
WHERE a.cycle != 1
其中第一个填充cycle_no,eacg循环为1,第二个填充所有其他行cycle_no值
您可以使用以下触发器来填充它(可能有更有效的方法)。
CREATE TRIGGER insert_mytable
BEFORE INSERT ON mytable
FOR EACH row
SET NEW.cycle_no = IF(NEW.cycle = 1, (SELECT MAX(cycle_no) + 1 FROM mytable WHERE cycle = 1 ), (SELECT MAX(cycle_no) FROM mytable WHERE cycle = 1 ));
然后你可以得到像这样的最新值(它依赖于cycle_no只递增1): -
SELECT z.*
FROM
(
SELECT b.cycle_no, MAX(b.cycle)
FROM mytable a
INNER JOIN mytable b
ON b.cycle_no = (a.cycle_no - 1)
WHERE a.cycle = 1
GROUP BY b.cycle_no
) Sub1
INNER JOIN mytable z
ON z.cycle_no = Sub1.cycle_no
在测试数据上我敲了一下(大约750万条记录),这需要大约53秒。不确定这是否可以用于你。