我得到了这样的mysql查询:
SELECT name,
(SELECT timePing
FROM TerminalPings
WHERE terminalsId = Terminals.id
ORDER BY timePing DESC LIMIT 1)
as timePing
FROM Terminals`
它运行良好,但我需要从TerminalPings中选择前2个timePing,并将它们命名为timePing1和timePing2。最好的方法是什么?
修改 opps,抱歉伙计们,但是TerminalPings和Terminals之间确实存在关系...我的坏:(我觉得忘记写WHERE声明是如此愚蠢:(
答案 0 :(得分:1)
第二次更新:
为更新的问题导出@OMG Ponies' solution:
SELECT t.name,
MAX(CASE WHEN x.rank = 1 THEN x.timeping END) AS timeping1,
MAX(CASE WHEN x.rank = 2 THEN x.timeping END) AS timeping2
FROM terminals t
LEFT JOIN (
SELECT tp.timeping, tp.terminalsId,
IF(@curId <> terminalsId, @rownum := 0, 0),
@rownum := @rownum + 1 AS rank,
@curId := terminalsId
FROM terminalPings tp
JOIN (SELECT @rownum := 0, @curId := 0) r
ORDER BY tp.terminalsId, tp.timeping DESC
) x ON (x.terminalsId = t.id AND x.rank <= 2)
GROUP BY t.name;
新测试用例:
CREATE TABLE terminals (id int, name varchar(20));
INSERT INTO terminals VALUES (1, 'Terminal 1');
INSERT INTO terminals VALUES (2, 'Terminal 2');
INSERT INTO terminals VALUES (3, 'Terminal 3');
CREATE TABLE terminalPings (terminalsId int, timePing int);
INSERT INTO terminalPings VALUES (1, 5);
INSERT INTO terminalPings VALUES (1, 8);
INSERT INTO terminalPings VALUES (1, 4);
INSERT INTO terminalPings VALUES (2, 6);
INSERT INTO terminalPings VALUES (2, 5);
INSERT INTO terminalPings VALUES (3, 4);
INSERT INTO terminalPings VALUES (3, 7);
INSERT INTO terminalPings VALUES (3, 2);
新结果:
+------------+-----------+-----------+
| name | timeping1 | timeping2 |
+------------+-----------+-----------+
| Terminal 1 | 8 | 5 |
| Terminal 2 | 6 | 5 |
| Terminal 3 | 7 | 4 |
+------------+-----------+-----------+
3 rows in set (0.00 sec)
EXPLAIN输出(MySQL 5.1.45)
+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------------------+
| 1 | PRIMARY | t | ALL | NULL | NULL | NULL | NULL | 3 | Using temporary; Using filesort |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 8 | |
| 2 | DERIVED | <derived3> | system | NULL | NULL | NULL | NULL | 1 | Using filesort |
| 2 | DERIVED | tp | ALL | NULL | NULL | NULL | NULL | 8 | |
| 3 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+------------+--------+---------------+------+---------+------+------+---------------------------------+
5 rows in set (0.00 sec)
更新: @OMG Ponies' solution比我之前建议的要快(请参阅两个答案的评论,原因)。我在这里留下答案供参考(这个答案仍然会返回一个正确的结果,当你在外部查询中有很多行时会慢得多:在终端表中)。
我仍然会使用两个单独的查询。虽然SQL是一种非常富有表现力的语言,但是不需要在一个查询中执行所有操作......就像在其他编程语言中不需要在单行代码中执行任务一样! MySQL使得下面的解决方案中的子查询无法访问的事实是您在使用复杂查询时可能遇到的一种潜在问题(可能很容易被分解为两个或更多非常简单的查询)。
上一个答案:
您可能希望使用两个单独的查询。但只是为了迎接挑战,您可能需要尝试以下方法:
SELECT name,
(
SELECT timePing FROM
(
SELECT timePing, @rowid := @rowid + 1 rownum
FROM TerminalPings, (SELECT @rowid := 0) rn
ORDER BY timePing DESC
LIMIT 1
) t
WHERE t.rownum = 1
) AS timePing_1,
(
SELECT timePing FROM
(
SELECT timePing, @rowid := @rowid + 1 rownum
FROM TerminalPings, (SELECT @rowid := 0) rn
ORDER BY timePing DESC
LIMIT 2
) t
WHERE t.rownum = 2
) AS timePing_2
FROM Terminals;
测试用例:
CREATE TABLE terminals (name varchar(20));
INSERT INTO terminals VALUES ('Terminal 1');
INSERT INTO terminals VALUES ('Terminal 2');
INSERT INTO terminals VALUES ('Terminal 3');
CREATE TABLE terminalPings (timePing int);
INSERT INTO terminalPings VALUES (1);
INSERT INTO terminalPings VALUES (2);
INSERT INTO terminalPings VALUES (3);
INSERT INTO terminalPings VALUES (4);
结果:
+------------+------------+------------+
| name | timePing_1 | timePing_2 |
+------------+------------+------------+
| Terminal 1 | 4 | 3 |
| Terminal 2 | 4 | 3 |
| Terminal 3 | 4 | 3 |
+------------+------------+------------+
3 rows in set (0.01 sec)
EXPLAIN输出(MySQL 5.1.45)(参见@OMG Ponies' answer的评论):
+----+----------------------+---------------+--------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+----------------------+---------------+--------+---------------+------+---------+------+------+----------------+
| 1 | PRIMARY | Terminals | ALL | NULL | NULL | NULL | NULL | 3 | |
| 5 | UNCACHEABLE SUBQUERY | <derived6> | ALL | NULL | NULL | NULL | NULL | 2 | Using where |
| 6 | DERIVED | <derived7> | system | NULL | NULL | NULL | NULL | 1 | Using filesort |
| 6 | DERIVED | TerminalPings | ALL | NULL | NULL | NULL | NULL | 4 | |
| 7 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 2 | UNCACHEABLE SUBQUERY | <derived3> | system | NULL | NULL | NULL | NULL | 1 | |
| 3 | DERIVED | <derived4> | system | NULL | NULL | NULL | NULL | 1 | Using filesort |
| 3 | DERIVED | TerminalPings | ALL | NULL | NULL | NULL | NULL | 4 | |
| 4 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+----------------------+---------------+--------+---------------+------+---------+------+------+----------------+
答案 1 :(得分:1)
使用:
SELECT t.name,
MAX(CASE WHEN x.rank = 1 THEN x.timeping END) AS timeping1,
MAX(CASE WHEN x.rank = 2 THEN x.timeping END) AS timeping2
FROM TERMINALS t
JOIN (SELECT tp.timeping,
@rownum := @rownum + 1 AS rank
FROM TERMINALPINGS tp
JOIN (SELECT @rownum := 0) r
ORDER BY tp.timeping DESC
LIMIT 2) x
GROUP BY t.name
我不认为TERMINALS
和TERMINALPINGS
之间没有任何关系。这意味着每个TERMINALS.name
值都具有相同的timeping
值...
EXPLAIN输出(MySQL 5.1.49)
id select_type table type possible_keys key key_len ref rows Extra
------------------------------------------------------------------------------------
1 'PRIMARY' '<derived2>' 'ALL' '' '' '' 2 'Using temporary; Using filesort'
1 'PRIMARY' 't' 'ALL' '' '' '' 3 'Using join buffer'
2 'DERIVED' '<derived3>' 'system' '' '' '' 1 'Using filesort'
2, 'DERIVED' 'tp' 'ALL' '' '' '' 4 ''
3 'DERIVED' '' '' '' '' '' 'No tables used'
EXPLAIN输出(MySQL 4.1)
id select_type table type possible_keys key key_len ref rows Extra
------------------------------------------------------------------------------------
1 'PRIMARY' 't' 'ALL' '' '' '' 3 'Using temporary; Using filesort'
1 'PRIMARY' '<derived2>' 'ALL' '' '' '' 2 ''
2 'DERIVED' '<derived3>' 'system' '' '' '' 1 'Using filesort'
2, 'DERIVED' 'tp' 'ALL' '' '' '' 4 ''
3 'DERIVED' '' '' '' '' '' 'No tables used'
答案 2 :(得分:0)
为什么使用子查询?这种情况是JOIN的完美候选人。