Mysql

是否有“軟” ORDER BY / GROUP BY?

  • November 14, 2018

SQL小提琴

http://sqlfiddle.com/#!9/c82c87b/1

表定義

首先,這是我的表:

CREATE TABLE `stackoverflow` (
`id` VARBINARY( 36 ) NOT NULL COMMENT 'GUID generated by PHP',
`time` TIME NOT NULL COMMENT 'Current time(stamp)',
`type` VARCHAR( 10 ) NOT NULL COMMENT 'start/stop',
`reference` VARBINARY( 36 ) NOT NULL COMMENT 'multiple starts/stops to one reference',
PRIMARY KEY ( `id` )
) ENGINE = MYISAM 

數據

這是一些範例數據:

INSERT INTO `stackoverflow` (
`id` ,
`time` ,
`type` ,
`reference`
)
VALUES 
('03bd8e91-b9aa-4d18-be47-9e9cce903cfd', '11:00:00', 'start', '76afe924-08aa-431b-904a-66290c50da6a'), 
('ef10860a-7666-4ca0-95b6-79ef2d5b3f75', '11:01:00', 'start', 'fd064ef5-462f-489c-ae14-3cb766eb80c4'), 
('9bc72e24-a0d4-43a3-86ab-973c331e2958', '11:02:00', 'stop', 'fd064ef5-462f-489c-ae14-3cb766eb80c4'), 
('a245cda3-1196-4dba-832e-0474fd0eb0bf', '11:03:00', 'start', '05324e7b-a358-48bb-9779-08cf60038bb8'), 
('488c67e6-c21d-4356-9578-49e857259345', '11:06:00', 'stop', '76afe924-08aa-431b-904a-66290c50da6a'), 
('11c0e4ac-e7e9-418a-841f-650ced3e8343', '11:12:00', 'stop', '05324e7b-a358-48bb-9779-08cf60038bb8');

它基本上是關於計時器 - 每個計時器(參考)都有多個啟動和停止。每個條目要麼是開始,要麼是停止。

查詢數據

要在 HTML 中顯示這些計時器,我需要像這樣對數據進行排序:

SELECT * FROM stackoverflow ORDER BY reference DESC, time ASC;

結果如下所示:

 ef10860a-7666-4ca0-95b6-79ef2d5b3f75  11:01:00    start   fd064ef5-462f-489c-ae14-3cb766eb80c4
 9bc72e24-a0d4-43a3-86ab-973c331e2958  11:02:00    stop    fd064ef5-462f-489c-ae14-3cb766eb80c4
# 03bd8e91-b9aa-4d18-be47-9e9cce903cfd  11:00:00    start   76afe924-08aa-431b-904a-66290c50da6a
# 488c67e6-c21d-4356-9578-49e857259345  11:06:00    stop    76afe924-08aa-431b-904a-66290c50da6a
 a245cda3-1196-4dba-832e-0474fd0eb0bf  11:03:00    start   05324e7b-a358-48bb-9779-08cf60038bb8
 11c0e4ac-e7e9-418a-841f-650ced3e8343  11:12:00    stop    05324e7b-a358-48bb-9779-08cf60038bb8

問題

  • 如何將標有**#**的行置於首位?
  • 我認為通過引用排序是錯誤的,但我如何將它們放在一起?只是按時間排序會產生錯誤的結果。如果這引用可以保持在一起,那就太好了。
  • 我需要虛擬表還是子查詢?

附加資訊

同時,我用多個單獨的 SQL 操作修復了 PHP 中的這個“‘SQL’問題”,詳細如下:

  1. 獲取所有參考
SELECT DISTINCT reference FROM stackoverflow;
  1. 對於每個參考
SELECT * FROM stackoverflow WHERE reference = :reference ORDER BY time;
  1. 對於每一行 -> 生成 HTML“計時器”

結果:

# 03bd8e91-b9aa-4d18-be47-9e9cce903cfd  11:00:00    start   76afe924-08aa-431b-904a-66290c50da6a
# 488c67e6-c21d-4356-9578-49e857259345  11:06:00    stop    76afe924-08aa-431b-904a-66290c50da6a
 ef10860a-7666-4ca0-95b6-79ef2d5b3f75  11:01:00    start   fd064ef5-462f-489c-ae14-3cb766eb80c4
 9bc72e24-a0d4-43a3-86ab-973c331e2958  11:02:00    stop    fd064ef5-462f-489c-ae14-3cb766eb80c4
 a245cda3-1196-4dba-832e-0474fd0eb0bf  11:03:00    start   05324e7b-a358-48bb-9779-08cf60038bb8
 11c0e4ac-e7e9-418a-841f-650ced3e8343  11:12:00    stop    05324e7b-a358-48bb-9779-08cf60038bb8

訂單現在符合預期 - 如果有一個 MySQL 解決方案,它仍然會很棒。:)


注意:確切的 MySQL 版本是5.1.61

SELECT s.* 
FROM stackoverflow s, ( SELECT reference, MIN(time) time
                       FROM stackoverflow
                       GROUP BY reference
                      ) o
WHERE s.reference = o.reference
ORDER BY o.time ASC, reference DESC, time ASC;

小提琴

一切都很簡單。您希望按組中最舊記錄的日期時間對組進行排序。子查詢獲取此資訊,並通過將其連接到組中的每個記錄來用於主查詢。為了理解輸出中的替換s.**分析結果。

從 8.0 版本開始,MySQL 支持視窗函式,包括視窗聚合函式。如果您負擔得起將 MySQL 實例升級到 8.0 版的費用,您可以使用如下簡單的查詢來解決您的問題:

SELECT
 *
FROM
 `stackoverflow`
ORDER BY
 MIN(`time`) OVER (PARTITION BY `reference`) ASC,
 `time` ASC
;

MIN(time) OVER (PARTITION BY reference)表達式返回每行的time最小值reference。在您的情況下,這將是開始時間(顯然,假設您的數據中沒有不一致)。這相當於按 對行進行分組reference,獲取MIN(time)每個組,然後在列上連接回原始表reference,只有在這種情況下,所有這些操作都有效地(儘管不是實際上)隱式地完成,只需使用上述表達式。

請注意,表達式返回的值將僅用於排序而不用於輸出。如果您實際上也想返回它們,請將表達式添加到SELECT列表中:

SELECT
 *,
 MIN(`time`) OVER (PARTITION BY `reference`) AS `start_time`
FROM
 `stackoverflow`
ORDER BY
 `start_time` ASC,
 `time` ASC
;

另一個注意事項是,此解決方案將適用於您的範例,但不一定適用於您的實際數據。在您的範例中,所有開始時間都不同,因此僅按排序MIN(time), time就足夠了。如果在您的實際數據中不同reference的行可以具有相同的開始時間,您將需要在排序reference之前額外排序,如Akinatime所建議的:

SELECT
 *,
 MIN(`time`) OVER (PARTITION BY `reference`) AS `start_time`
FROM
 `stackoverflow`
ORDER BY
 `start_time` ASC,
 `reference` ASC,
 `time` ASC
;

引用自:https://dba.stackexchange.com/questions/222416