是否有“軟” ORDER BY / GROUP BY?
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’問題”,詳細如下:
- 獲取所有參考
SELECT DISTINCT reference FROM stackoverflow;
- 對於每個參考
SELECT * FROM stackoverflow WHERE reference = :reference ORDER BY time;
- 對於每一行 -> 生成 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 ;