Sliding certain records to the end of a run of the same date

百般思念 提交于 2020-01-22 02:16:11

问题


I have three columns -

  • TheDate - Obviously a date.
  • TheID - A strictly increasing ID.
  • TheType - A Record type.

I want these to sort by TheID in almost all cases except for just one record type. Records of the special record type must appear at the end of all records with the same date.

Example:

I want the record type 101 to appear after all other records that have the same date. In all other cases TheID controls the order.

My attempt goes like:

ORDER BY 
TheDate, 
CASE WHEN TheType = 101 THEN 1 ELSE 0 END, 
TheID

which nearly does what I want but is doing far more - i.e. it will reorder by TheDate which is not waht I want.

If the same date occurs later in the data I don't care - it's just when a sequence of records containing a type 101 (when sorted by TheID) all have the same date I want type 101 to be last.


回答1:


This is complicated. First you must find consecutive date records, so with

thedate     theid  thetype
2014-07-12   5001       59
2014-07-12   5002      101
2014-07-12   5003       88
2014-07-13   5004       10
2014-07-12   5005       60

you would identify 2014-07-12 as one occurrence for the first three records and another for the last record. The second record would have to get position #3 in your results, not #5.

You achieve this by giving consecutive records a group key by using first LAG to look into the previous record, thus creating a flag on group change, and then cumulating these flags.

select thedate, theid, thetype
from
(
  select 
    thedate, theid, thetype,
    sum(new_group) over (order by theid) as group_key
  from
  (
    select
      thedate, theid, thetype,
      case when lag(thedate) over (order by theid) = thedate then 0 else 1 as new_group
    from mytable
  ) marked
) grouped
order by 
  group_key,
  case when thetype = 101 then 1 else 0 end,
  theid;



回答2:


If TheID cannot be null then just change the TheID to null as part of the order by where TheType is a special value:

order by TheDate, 
         case TheType
           when 101 then null
           else TheID
         end nulls last



回答3:


Taking the liberty granted in comments to assume that TheDate is non-decreasing with ascending TheId, if r1.TheId < r2.TheId then it must be the case that r1.TheDate <= r2.TheDate (that's the definition of non-decreasing). In that case, ordering first by TheDate and then by TheId produces the same order as ordering by TheId alone. Looking at it from the other direction, ordering by TheId automatically produces results clustered by TheDate and in order by date.

But what you're already doing differs from ordering by (TheDate, TheId) (which we already established is the same as ordering by just TheId) only by moving the special records to the end of each date cluster, which is exactly what you say you want. Thus, you must be getting your results in the desired order; if you in fact have any problem then it must be that you are dissatisfied with the means by which you are doing so. For instance, perhaps you are concerned with query performance.

If your existing ordering indeed produces the correct results, however, then I'm having trouble seeing an alternative that I would expect to deliver substantially better performance. No doubt the ordering can be produced by means that do not rely on TheDate to be non-decreasing, but I would expect all of those to be comparatively expensive to compute.



来源:https://stackoverflow.com/questions/32949673/sliding-certain-records-to-the-end-of-a-run-of-the-same-date

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!