这是来自带汇总的mysql的示例结果
|country | region | value | |--------|--------|--------| | us | west | 5 | | us | east | 15 | | us | north | 10 | | us | total | 30 | | uk | west | 3 | | uk | east | 2 | | uk | north | 1 | | uk | total | 6 | | total | total | 36 |
我想像这样排序值列,保留总行位置
ASC
| us | west | 5 | | us | north | 10 | | us | east | 15 | | us | total | 30 | | uk | north | 1 | | uk | east | 2 | | uk | west | 3 | | uk | total | 6 | | total | total | 36 |
DESC
| us | east | 15 | | us | north | 10 | | us | west | 5 | | us | total | 30 | | uk | west | 3 | | uk | east | 2 | | uk | north | 1 | | uk | total | 6 | | total | total | 36 |
这是一个查询示例:
SELECT * FROM ( SELECT COALESCE(country, 'total') AS country, COALESCE(region, 'total' ) AS region, SUM('value'), FROM table GROUP BY country ASC, region ASC WITH ROLLUP ) t ORDER BY ... maybe something to do here ...
也许基于正则表达式的排序顺序? 或者使用mysql字符串函数?
我不知道如何解决我的问题
感谢提前寻求帮助
...
在你的帮助和经过一些个人反思之后 我想我现在有一个很好的方法来做这件事
SELECT * FROM ( SELECT IF(IFNULL(country, 1),'total',NULL) AS country, IF(IFNULL(region, 1),'total',NULL) AS region, COALESCE(country, 'Total') AS country1, COALESCE(region, 'Total') AS region1, SUM(value) as `value to sort` FROM data_table GROUP BY country, region WITH ROLLUP ) t ORDER BY country IS NULL DESC, country1 ASC, region IS NULL DESC, ... ... `value to sort` DESC (or) ... `value to sort` ASC
即使使用DESC排序,我总是在聚合和子聚合值之后总计和子总数: - )
你认为这是一个好方法吗? 它在所有情况下都适合我答案 0 :(得分:2)
基于Johan's answer的原始版本:
SELECT *
FROM (
SELECT
COALESCE(country, 'total') AS country,
COALESCE(region, 'total' ) AS region,
SUM(`value`) as `value`,
FROM `table`
GROUP BY country, region WITH ROLLUP
) t
ORDER BY country = 'total', country, region = 'total', `value`
这个技巧的工作方式是,如果country = 'total'
列等于country
,则表达式'total'
的计算结果为1(真),否则计算结果为0(假)。按升序排列,1在0之后。因此,按该表达式排序会强制country
列等于'total'
的任何行在任何其他列之后排序。
同样,在region = 'total'
之前按表达式value
排序会强制'total'
中值region
的任何行在具有相同{{1}的任何其他行之后排序}},无论他们的country
列如何。
同样的技巧也适用于其他comparison operators。例如,如果您想强制使用负值对正值进行排序,则可以按value
对行进行排序。
答案 1 :(得分:0)
with rollup
生成的总计行具有非聚合行的所有零值
您可以利用它来强制该行为最后一个(或第一个)。
试试这个,没有测试过,所以我不是百分百确定:
SELECT
ti2.country
, ti2.region
,ti2.`value`
FROM table1 to1
INNER JOIN (SELECT
t2.country
,IFNULL(ti1.region,'subtotal') as country
,ti1.`value`
FROM (
SELECT
t1.country
, t1.region
, SUM(t1.`value`) as `value`
FROM table1 t1
WHERE t1.country = to1.country
GROUP BY country, region WITH ROLLUP) ti1 ) ti2
ON (ti2.country = to1.country)
GROUP BY country, region WITH ROLLUP
ORDER BY country, region = 'subtotal', region
请注意,order by子句应该进入外部(!)选择,而不是内部选择
(我知道内部选择的顺序在大多数情况下都有效,但是当查询变得复杂时,它会搞砸并让你偏离轨道)
还要注意,依赖行为构建到MySQL的group by
子句中的非标准隐式顺序并不是一个好主意;最好坚持使用标准SQL,除非获得明显的好处。
答案 2 :(得分:0)
这很棘手!我做了一个(相当大的)假设你有一个countryId列可以在你的源表中使用,它唯一地标识表中的每个国家(所以'us'有countryId = 1,'uk'有countryId = 2等等)。如果你不这样做,你总是可以添加一个:
-- Descending
SELECT *
FROM (
SELECT
COALESCE(country, 'total') AS pays,
COALESCE(region, 'total' ) AS region,
SUM(value) as value,
(SUM(value) * (CASE WHEN COALESCE(region, 'total') = 'total' THEN 1 ELSE -1 END)
+ countryId*(SELECT SUM(value) FROM test_table)
+ CASE WHEN COALESCE(country, 'total') = 'total'
THEN (SELECT SUM(value) FROM test_table) ELSE 0 END) as rank1
FROM test_table
GROUP BY country, region WITH ROLLUP
) t
ORDER BY rank1 asc;
-- Ascending
SELECT *
FROM (
SELECT
COALESCE(country, 'total') AS pays,
COALESCE(region, 'total' ) AS region,
SUM(value) as value,
(SUM(value) + countryId*(SELECT SUM(value) FROM test_table)
+ CASE WHEN COALESCE(country, 'total') = 'total'
THEN (SELECT SUM(value) FROM test_table) ELSE 0 END) as rank1
FROM table
GROUP BY country, region WITH ROLLUP
) t
order by rank1 asc;
不是最漂亮的,当然不是最干净的,但应该帮助你。