问题
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