我现在头发都白了…
我有一张这样的桌子。
ID - Place - Person
1 - London - Anna
2 - Stockholm - Johan
3 - Gothenburg - Anna
4 - London - Nils
我想得到包含所有不同人的结果,但我想选择按哪个地方点单。
例如。我想要一份按伦敦订购的名单,其余的将会跟进,但在PERSON上是不同的。
Output like this:
ID - Place - Person
1 - London - Anna
4 - London - Nils
2 - Stockholm - Johan
尝试:
SELECT ID, Person
FROM users
ORDER BY FIELD(Place,'London'), Person ASC "
但是它给了我:
ID - Place - Person
1 - London - Anna
4 - London - Nils
3 - Gothenburg - Anna
2 - Stockholm - Johan
我真的不希望Anna,或者任何人,不止一次出现在结果中。
这是获得指定输出的一种方法,但它使用MySQL特定的行为,这是不保证的:
SELECT q.ID
, q.Place
, q.Person
FROM ( SELECT IF(p.Person<=>@prev_person,0,1) AS r
, @prev_person := p.Person AS person
, p.Place
, p.ID
FROM users p
CROSS
JOIN (SELECT @prev_person := NULL) i
ORDER BY p.Person, !(p.Place<=>'London'), p.ID
) q
WHERE q.r = 1
ORDER BY !(q.Place<=>'London'), q.Person
该查询使用内联视图按Person的特定顺序返回所有行,以便所有"Anna"行在一起,然后是所有"Johan"行,等等。每个人的行集按Place='London'
排序,然后按ID排序。
"诀窍"是使用MySQL用户变量来比较当前行的值与前一行的值。在这个例子中,我们检查当前行上的'Person'是否与前一行上的'Person'相同。根据该检查,如果这是我们正在处理的a人的"第一行",则返回1,否则返回0。
最外层的查询处理来自内联视图的行,并为每个Person排除除"第一行"之外的所有行(我们从内联视图返回的0或1)
(这不是获得结果集的唯一方法。但这是模拟分析函数的一种方法,其他RDBMS中也有。
为了便于比较,在MySQL以外的数据库中,我们可以这样使用SQL:
SELECT ROW_NUMBER() OVER (PARTITION BY t.Person ORDER BY
CASE WHEN t.Place='London' THEN 0 ELSE 1 END, t.ID) AS rn
, t.ID
, t.Place
, t.Person
FROM users t
WHERE rn=1
ORDER BY CASE WHEN t.Place='London' THEN 0 ELSE 1 END, t.Person
后续
在答案的开头,我提到MySQL的行为是不保证的。我指的是在SQL语句中使用MySQL用户定义变量。
摘自MySQL 5.5参考手册http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
"作为一般规则,除了在SET语句中,永远不要给用户变量赋值并在同一语句中读取该值。"
"对于其他语句,例如SELECT,您可能会得到预期的结果,但这并不能保证。"
"包含用户变量的表达式的求值顺序未定义。"
试试这个:
SELECT ID, Place, Person
FROM users
GROUP BY Person
ORDER BY FIELD(Place,'London') DESC, Person ASC;
你想用group by
代替distinct
:
SELECT ID, Person
FROM users
GROUP BY ID, Person
ORDER BY MAX(FIELD(Place, 'London')), Person ASC;
GROUP BY
和SELECT DISTINCT
做同样的事情。但是,您可以在子句中提到其他字段,例如HAVING
和ORDER BY
。