简体   繁体   中英

Comparing values on previous row to perform calculations on the current row, SQL

sql fiddle: http://sqlfiddle.com/#!4/a717b/1

Here is my Table: 在此处输入图片说明

Here is my Code:

select key, status, dat, sysdat, (case when key = 1 and type = 'Car' status = 'F' then round( sysdat-dat,2) else 0 end ) as Days, (case when key = 1 and type ='Bus' and Status = 'F' then round( sysdat-dat,2) else 0 end) as Days from ABC

Expected Output:

So I want to calculate days between the 'dat' column and current date for the following conditions.

1) For every key, The sequence is always car first, bus second. which means that for every key, only when the status of the car is true we check for the bus.

2) If the Status OF 'CAR' IS 'T' then I don't want to calculate the days

3) If the Status of 'Car' IS 'F' then I want to calculate the days only for the 'Car' and not for 'Bus' because it is always 'car' first 'bus' second

4) If the Status of 'Bus' is 'F' and Status of 'Car' is 'T' then I calculate the days because it matches the condition, 'Car' first and 'Bus' second. 是

With 2 vehicles

If you always have a car and a bus, and only a car and a bus of the same key, you could self-join the table, and check if either the vehicle a (which you're querying) is Car with status F, or if the related verhicle, b , is a car with status T. In either case you're gonna get a date, and in any other case you don't. That covers your example, and also implies that if car and bus would both be T, the date would still be shown next to the bus only.

select a.key, a.type, a.status, a.dat,
  case when 
    (a.type = 'car' and a.Status = 'F') or -- a is a car and is F
    (b.type = 'car' and b.Status = 'T') -- a is related to a car (b), which is T
  then
    trunc(sysdate) - a.dat
  end as DAYS
from 
  ABC a
  join ABC b on b.key = a.key and b.type <> a.type
order by
  -- Sort the query by key first, then type.
  a.key, 
  decode(a.type, 'car', 1, 2)

The query above: http://sqlfiddle.com/#!4/a717b/5/0

With N vehicles

If you have more vehicles, a different approach can be better, especially when the number of vehicles is high, or not fixed.

The query below has a list of all the vehicles and their sort order. This is an inline view now, but you could use a separate lookup table for that. A lookup table is even more flexible, because you can just add vehicle types or change their sort order.

Anyway, that lookup table/view can be joined on your main table to have a sort order for each of your record.

You can then make a ranking using window function like rank or dense_rank to introduce a numbering based on that sort order ("falsenumber"), and the fact that status is 'F'. After that, it's easy to put the date on the first row that is F (falsenumber = 1).

with
  VW_TYPES as
  -- This could be a lookup table as well, instead of this hard-codeslist of unions.
  ( select 'car' as type, 1 as sortorder from dual union all
    select 'bus' as type, 2 as sortorder from dual union all
    select 'train' as type, 3 as sortorder from dual union all
    select 'airplane' as type, 4 as sortorder from dual union all
    select 'rocket' as type, 5 as sortorder from dual),

  VW_TYPESTATUS as
  ( select
      a.*,
      t.sortorder,
      dense_rank() over (partition by key order by case when a.status = 'F' then t.sortorder end) as falsenumber
    from
      ABC a
      join VW_TYPES t on t.type = a.type)

select
  ts.key, ts.type, ts.status, ts.dat, 
  case when ts.falsenumber= 1 then
    trunc(sysdate) - ts.dat
  end as DAYS
from
  VW_TYPESTATUS ts
order by
  ts.key, ts.sortorder

The query above: http://sqlfiddle.com/#!4/71f52/8/0

Vehicle types in a separate table: http://sqlfiddle.com/#!4/f055d/1/0

SQL Fiddle结果的屏幕截图

Do note that oracle is case sensitive. 'car' and 'Car' and 'CAR' are not the same thing. Use lower(type) = 'car' if you want to allow type to contain the vehicle type with any casing. Do note that that's bad for using indexes, although I think the impact isn't that bad, since you only got a couple of rows per key.

Alternatively (arguably better), you could introduce a numeric VehicleTypeId in the new types table, and use that id in the ABC table, instead of the string 'Car'.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM