查询每组代码的前N个适用于MySQL,但对于MariaDB有不同的结果

6 mysql sql mariadb

我有一个SQL查询,它提取每组的最新3条记录.MySQL的查询结果与MariaDB不同.此查询在下面的sqlfiddle中实现

http://sqlfiddle.com/#!9/c09fe/2

表的内容

CREATE TABLE tmp
    (`mac_addr` varchar(10), `reader_name` varchar(22), `value` numeric, `time_change` datetime)
;

INSERT INTO tmp
    (`mac_addr`, `reader_name`, `value`, `time_change`)
VALUES
    ('''B99A88''', '''name_8''', 1, '2016-07-07 19:21:48'),
    ('''B99A88''', '''own__detect_1''', 1, '2016-06-21 13:30:00'),
    ('''B99A88''', '''own__temperature_1''', 37.4, '2016-05-04 18:23:03'),
    ('''B99A88''', '''own__temperature_1''', 29.4, '2016-05-04 18:19:33'),
    ('''B99A88''', '''own__temperature_1''', 28.4, '2016-05-04 18:17:32'),
    ('''B99A88''', '''own__temperature_1''', 27.4, '2016-05-04 18:04:08'),
    ('''B99A88''', '''own__temperature_1''', 21.4, '2016-05-04 15:11:42'),
    ('''B99A88''', '''own__detect_1''', 0, '2016-04-20 15:22:23'),
    ('''B99A88''', '''own__detect_1''', 1, '2016-04-15 17:39:52'),
    ('''B99A88''', '''own__detect_1''', 0, '2016-04-15 17:39:46'),
    ('''B99A88''', '''own__detect_1''', 1, '2016-04-11 17:34:00'),
    ('''B99A88''', '''own__detect_1''', 1, '2016-04-11 17:33:00'),
    ('''B99A88''', '''own__detect_1''', 0, '2016-04-11 17:33:00'),
    ('''B99A88''', '''own__temperature_1''', 28.4, '2016-04-10 21:20:20'),
    ('''B99A88''', '''own__temperature_1''', 32.5, '2016-04-10 21:00:00'),
    ('''B99A88''', '''own__temperature_1''', 34.2, '2016-04-10 11:29:00')
;
Run Code Online (Sandbox Code Playgroud)

查询以提取每个组的最新3条记录.

SELECT mac_addr, reader_name, value, time_change
FROM (
    SELECT t1.*,
           IF(@rn = reader_name, @rowno := @rowno + 1, @rowno := 1) AS rowno,
           @rn := reader_name
    FROM (
        SELECT *
          FROM tmp
        ORDER BY reader_name, time_change DESC
    ) t1
    CROSS JOIN (SELECT @rn := null, @rowno := 0) t2
) t
WHERE rowno <= 3
Run Code Online (Sandbox Code Playgroud)

使用MySQL v5.6时的结果如下;

mac_addr    reader_name             value   time_change
'B99A88'    'name_8'                 1      July, 07 2016 19:21:48
'B99A88'    'own__detect_1'          1      June, 21 2016 13:30:00
'B99A88'    'own__detect_1'          0      April, 20 2016 15:22:23
'B99A88'    'own__detect_1'          1      April, 15 2016 17:39:52
'B99A88'    'own__temperature_1'    37      May, 04 2016 18:23:03
'B99A88'    'own__temperature_1'    29      May, 04 2016 18:19:33
'B99A88'    'own__temperature_1'    28      May, 04 2016 18:17:32
Run Code Online (Sandbox Code Playgroud)

MySQL的结果就是我想要的.但是,我使用的是MariaDB,结果与MySQL结果不同.

MariaDB结果如下所示;

mac_addr    reader_name             value   time_change
'B99A88'    'name_8'                 1      2016-07-07 19:21:48
'B99A88'    'own__detect_1'          1      2016-06-21 13:30:00
'B99A88'    'own__temperature_1'    37      2016-05-04 18:23:03
'B99A88'    'own__temperature_1'    29      2016-05-04 18:19:33
'B99A88'    'own__temperature_1'    28      2016-05-04 18:17:32
'B99A88'    'own__detect_1'          0      2016-04-20 15:22:23
'B99A88'    'own__detect_1'          1      2016-04-15 17:39:52
'B99A88'    'own__detect_1'          0      2016-04-15 17:39:46
'B99A88'    'own__temperature_1'    28      2016-04-10 21:20:20
'B99A88'    'own__temperature_1'    33      2016-04-10 21:00:00
'B99A88'    'own__temperature_1'    34      2016-04-10 11:29:00
Run Code Online (Sandbox Code Playgroud)

如何修改查询代码,以便MariaDB的查询输出可以与MySQL相同?在MariaDB中使用窗口函数是个好主意吗?

Gor*_*off 3

ORDER BY正在使用的有两个键:

    ORDER BY reader_name, time_change DESC
Run Code Online (Sandbox Code Playgroud)

但是,这些键并不唯一标识每一行。因此,无法保证键相同的行的排序——即使在同一数据库上的两次查询运行之间也是如此。正常的解决方案是添加一个唯一的 id 列作为最后一个ORDER BY键,以便唯一标识每一行。

更一般地,在 SQL 中,ORDER BY不使用稳定排序。稳定排序是当键相同时保留键的原始顺序的排序。原因很简单。SQL 表和结果集表示无序集。没有要保留的初始订单。

如果您有主键列,那么将ORDER BY是:

    ORDER BY reader_name, time_change DESC, pk
Run Code Online (Sandbox Code Playgroud)

其余代码不需要更改。您只希望排序稳定。