mysql uses union all to cause sorting errors

1. Priority of sql keyword execution

First, before we understand this sorting error, we need to have a basic understanding of the priority of SQL keyword execution.

Keywords priority
join 1
where 2
group by 3
having 4
order by 5
limit 6

And union is a weird thing, it happens to be sandwiched between having and order by. If you want to calculate it, it can be calculated as 4.5.

Looking at this table, we can give an example

select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                        audit_date
                    from jinhuan_sales_order
                    where supervise ='已送审'
					group by order_number

                    union all

                    select
                        '采购订单审批' as order_type,
                        '待审批' as status,
                        o.order_number,
                        o.supplier_name,
                        o.make_person,
                        o.for_review_date,
                        d.total_price,
                        o.currency,
                        o.audit_date
                    from table1 o
                    left join (select main_code,sum(tax_money) total_price from table2 group by main_code
                    ) d on d.main_code = o.order_number
                    where o.supervise = '已送审'
					group by order_number

--得出结果
销售订单审批	待审批	XSDD20230609001	xx	陆雪	2023-06-09	19050.00		2023-06-16
销售订单审批	待审批	XSDD20230609002	xxx	2023-06-09	33750.00		2023-06-16
销售订单审批	待审批	XSDD20230610003	xxxxx	管理员	2023-06-10	200000.00		2023-06-16
采购订单审批	待审批	CGDD20230610004	xxxxxx	管理员	2023-06-11	40000.000	人民币	

--而我们将里面分组的内容改为order by时就会报一个错误
-- > 1221 - Incorrect usage of UNION and ORDER BY

2. Solution

2.1 Only one order by is used in a statement, and it is used at the end

select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                        audit_date
                    from jinhuan_sales_order
                    where supervise ='已送审'

                    union all

                    select
                        '采购订单审批' as order_type,
                        '待审批' as status,
                        o.order_number,
                        o.supplier_name,
                        o.make_person,
                        o.for_review_date,
                        d.total_price,
                        o.currency,
                        o.audit_date
                    from table1 o
                    left join (select main_code,sum(tax_money) total_price from table2 group by main_code
                    ) d on d.main_code = o.order_number
                    where o.supervise = '已送审'
					order by order_number

2.2 Wrap them in parentheses and let them execute alone (it works, but the result is wrong)

 (select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                        audit_date
                    from table
                    where supervise ='已送审'
					order by for_review_date desc)
                   
                    union all

                    (select
                        '采购订单审批' as order_type,
                        '待审批' as status,
                        o.order_number,
                        o.supplier_name,
                        o.make_person,
                        o.for_review_date,
                        d.total_price,
                        o.currency,
                        o.audit_date
                    from table o
                    left join (select main_code,sum(tax_money) total_price from table1 group by main_code
                    ) d on d.main_code = o.order_number
                    where o.supervise = '已送审'
					order by for_review_date desc)

Insert image description here

3. More complex situations

When the sort fields of the upper and lower SQLs are different, problems may still occur, for example

(select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                        audit_date
                    from table
                    where supervise ='已送审'
					order by for_review_date desc
                   )
                    union all

                   (       select
                          '销售订单审批' as order_type,
                          supervise as status,
                          sa_orderno as order_number,
                          cust_shortname as supplier_name,
                          makerman as make_person,
                          for_review_date,
                          total_price,
                          currency,
                          audit_date
                      from table
                      where (supervise ='审核通过' or supervise ='审核拒绝')
                      and datediff(current_date(),audit_date) <=7
					order by audit_date desc )

# 查询结果

Insert image description here
It can be seen that neither the unapproved documents nor the approved documents are sorted in the desired direction. In this case, the sorting is directly optimized by MySQL.

3.1 Use limit to force execution

(select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                        audit_date
                    from table
                    where supervise ='已送审'
					order by for_review_date desc
                   limit 999)
                    union all

                   (       select
                          '销售订单审批' as order_type,
                          supervise as status,
                          sa_orderno as order_number,
                          cust_shortname as supplier_name,
                          makerman as make_person,
                          for_review_date,
                          total_price,
                          currency,
                          audit_date
                      from table
                      where (supervise ='审核通过' or supervise ='审核拒绝')
                      and datediff(current_date(),audit_date) <=7
					order by audit_date desc 
					limit 999)

The result is as follows:
Insert image description here
two separate sql are spliced ​​according to the result we want.

3.2. Tried by myself (may not be 100% correct)

   select
                t.order_type,
                t.status,
                t.order_number,
                t.supplier_name,
                t.make_person,
                t.for_review_date,
                t.total_price,
                t.currency,
								t.audit_date
            from(
                    select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                       audit_date

                    from table
                    where supervise ='已送审'
                   

                    union all

                    select
                        '采购订单审批' as order_type,
                        '待审批' as status,
                        o.order_number,
                        o.supplier_name,
                        o.make_person,
                        o.for_review_date,
                        d.total_price,
                        o.currency,
                        o.audit_date
                    from table o
                    left join (select main_code,sum(tax_money) total_price from table1 group by main_code
                    ) d on d.main_code = o.order_number
                    where o.supervise = '已送审'
                  

                    union all

                    select
                        '盘点结果审批' as order_type,
                        '待审批' as status,
                        counting_code,
                        '公司' as supplier_name,
                        make_person,
                        for_review_date,
                        '' total_price,
                        '' currency,
                        approval_date as audit_date
                    from table
                    where approval_status = 2
                   order by for_review_date desc
                     
                 ) t
      
        union all

    
            select
                t.order_type,
                t.status,
                t.order_number,
                t.supplier_name,
                t.make_person,
                t.for_review_date,
                t.total_price,
                  t.currency,
								t.audit_date
            from(
                      select
                          '销售订单审批' as order_type,
                          supervise as status,
                          sa_orderno as order_number,
                          cust_shortname as supplier_name,
                          makerman as make_person,
                          for_review_date,
                          total_price,
                          currency,
                          audit_date
                      from table
                      where (supervise ='审核通过' or supervise ='审核拒绝')
                      and datediff(current_date(),audit_date) <=7
                     
                   

                      union all

                      select
                          '采购订单审批' as order_type,
                          supervise as status,
                          order_number,
                          supplier_name,
                          make_person,
                          for_review_date,
                          d.total_price,
                          o.currency,
                          o.audit_date
                      from table o
                      left join (select main_code,sum(tax_money) total_price from table1 group by main_code
                      ) d on d.main_code = o.order_number
                      where (supervise = '审核通过' or supervise ='审核拒绝')
                      and datediff(current_date(),audit_date) <=7
                     

                      union all

                      select
                          '盘点结果审批' as order_type,
                          '审核通过' as status,
                          counting_code,
                          '公司' as supplier_name,
                          make_person,
                          for_review_date,
                          '' total_price,
                          '' currency,
                          approval_date as audit_date
                      from table
                      where approval_status = 1
                      and datediff(current_date(),for_review_date) <=7
                      order by audit_date desc
                 ) t

The result is obtained:
Insert image description here
The result is actually correct, but I found that there is a problem in bringing up a single one.

 select
                t.order_type,
                t.status,
                t.order_number,
                t.supplier_name,
                t.make_person,
                t.for_review_date,
                t.total_price,
                t.currency,
				t.audit_date
            from(
                    select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                       audit_date
                    from table
                    where supervise ='已送审'
					order by for_review_date desc
                   )t
									 
			union all

    
            select
                t.order_type,
                t.status,
                t.order_number,
                t.supplier_name,
                t.make_person,
                t.for_review_date,
                t.total_price,
                t.currency,
				t.audit_date
            from(
                      select
                          '销售订单审批' as order_type,
                          supervise as status,
                          sa_orderno as order_number,
                          cust_shortname as supplier_name,
                          makerman as make_person,
                          for_review_date,
                          total_price,
                          currency,
                          audit_date
                      from table
                      where (supervise ='审核通过' or supervise ='审核拒绝')
                      and datediff(current_date(),audit_date) <=7
					order by audit_date desc
                 ) t

Insert image description here
I found that the order was still wrong. . So it’s very strange why the long list above me takes effect.

3.3 Final solution

Now think about it again, since the orders to be approved only need the submission time, and the approved orders only need the approval time, then it is enough to combine these two fields, and then set a flag to prioritize the status. sort

select
				2 flag,
                t.order_type,
                t.status,
                t.order_number,
                t.supplier_name,
                t.make_person,
                t.for_review_date,
                t.total_price,
                t.currency,
				t.audit_date
            from(
                    select
                        '销售订单审批' as order_type,
                        '待审批' as status,
                        sa_orderno as order_number,
                        cust_shortname as supplier_name,
                        makerman as make_person,
                        for_review_date,
                        total_price,
                        currency,
                       audit_date
                    from table
                    where supervise ='已送审'
                   )t
									 
			union all

    
            select
				1 flag,
                t.order_type,
                t.status,
                t.order_number,
                t.supplier_name,
                t.make_person,
                t.for_review_date,
                t.total_price,
                t.currency,
				t.audit_date
            from(
                      select
                          '销售订单审批' as order_type,
                          supervise as status,
                          sa_orderno as order_number,
                          cust_shortname as supplier_name,
                          makerman as make_person,
                          audit_date for_review_date,
                          total_price,
                          currency,
                          audit_date
                      from table
                      where (supervise ='审核通过' or supervise ='审核拒绝')
                      and datediff(current_date(),audit_date) <=7
                 ) t
				order by flag desc,for_review_date desc

Insert image description here
It can be concluded that the final sorting is correct

4 Conclusion

1. It is okay to use order by at the end when the sorting fields are the same.
2. When the sorting fields are not the same, you can use limit to achieve the conclusion you want, but it is not suitable for use in code.
3. It is okay. Sort by merging two fields into a new field

Guess you like

Origin blog.csdn.net/weixin_52796198/article/details/131303999