通过 order by 和 row_number 通过 mariadb 中的用户变量排序

sorting via order by and row_number via user variable in mariadb

我读到任何按操作排序的操作都是在查询结束时完成的,因此之前不能对结果强制排序。

因此,我想要实现的是通过使用分配行号的变量和使用 having 子句从具有重复项的结果中仅获取一条记录,我只 select 第一行。

抱歉我的解释不当,我希望你看一下这个就明白我的意思了:

select *
from address left join
(select address.add_nr as add_nr, acc.typ as typ, acc.seq as seq,
@num := if(@add_nr = address.add_nr, @num + 1, 1) as row_number,  
@add_nr := address.add_nr as dummy
from 
address left join


(

select con_add_nr as add_nr, 'XY' as typ, 1 as seq
from conctract,conctractdet
where con_pol_kz IN('L')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
group by 1,2,3

union
select ris_add_nr as add_nr, 'XX' as typ, 4 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and con_nr=ris_con_nr
and ris_art='VP'
group by 1,2,3


union
select ris_add_nr as add_nr, 'YY' as typ, 3 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and vrs_nr=ris_vrs_nr
and ris_art='VP'
group by 1,2,3


union
select ris_add_nr as add_nr, 'YX' as typ, 5 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and con_nr=ris_con_nr
and ris_art='2. VN'
group by 1,2,3


union
select ris_add_nr as add_nr, 'X' as typ, 2 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and vrs_nr=ris_vrs_nr
and ris_art='2. VN'
group by 1,2,3

order by add_nr,seq asc) as acc on acc.add_nr=address.add_nr
having row_number=1) as acc on address.add_nr=acc.add_nr;

所以问题在于,当 row_number 已经被假定时,操作顺序是在最后完成的。我需要的是先按序号"seq"对结果进行排序,实现第一个条目得到row_number=1。目前 "unsorted" 结果中的第一个条目得到 row_number=1 而这不是我需要的。

不要将 HAVING 与您使用用户变量动态生成的列一起使用。 MySQL 执行了一些将其搞砸的优化。相反,在外部查询中使用 WHERE 子句。

select *
from address left join
(select address.add_nr as add_nr, acc.typ as typ, acc.seq as seq,
@num := if(@add_nr = address.add_nr, @num + 1, 1) as row_number,  
@add_nr := address.add_nr as dummy
from 
address 
cross join (select @add_nr := 0, @num := 0) AS init
left join


(

select con_add_nr as add_nr, 'XY' as typ, 1 as seq
from conctract,conctractdet
where con_pol_kz IN('L')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
group by 1,2,3

union
select ris_add_nr as add_nr, 'XX' as typ, 4 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and con_nr=ris_con_nr
and ris_art='VP'
group by 1,2,3


union
select ris_add_nr as add_nr, 'YY' as typ, 3 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and vrs_nr=ris_vrs_nr
and ris_art='VP'
group by 1,2,3


union
select ris_add_nr as add_nr, 'YX' as typ, 5 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and con_nr=ris_con_nr
and ris_art='2. VN'
group by 1,2,3


union
select ris_add_nr as add_nr, 'X' as typ, 2 as seq
from conctract,conctractdet,risaddress
where con_pol_kz IN('P','PU','A')
and con_nr=vrs_con_nr
and cond_spa_nr IN (102,160,173)
and vrs_nr=ris_vrs_nr
and ris_art='2. VN'
group by 1,2,3

order by add_nr,seq asc) as acc on acc.add_nr=address.add_nr) as acc on address.add_nr=acc.add_nr
WHERE row_number = 1;

此优化在 documentation

中简要提及

HAVING is merged with WHERE if you do not use GROUP BY or aggregate functions (COUNT(), MIN(), and so on).

这意味着如果它可以像 WHERE 一样对待 HAVING 子句,它就会这样做,因此它会在生成结果集时从结果中删除行,而不是等到生成所有结果行。