简体   繁体   中英

How to select the field value if field in all child records are the same

I don't know if I'm wording this question correctly, but here it goes.

This is a web application using java, oracle, hibernate.

I have 2 tables in a one (items) to many (tasks) relationship.

Items

  • item_id name
  • active_status
  • etc

Tasks

  • task_id
  • item_id
  • active_status
  • progress_status
  • etc

The item's status is made up of the statuses of all of its tasks. Here's the logic...

  • If Item Status is Canceled or On Hold...return Item Active Status
  • If there are no tasks, return Completed
  • If All Tasks are Active and NOT Superseded, then
  • ...return Not Started if all tasks are Not Started
  • ...return Completed if all tasks are Completed
  • ...return On Hold if all tasks are On Hold
  • Otherwise return Started

I want to do this using SQL and map it to a field in my hibernate mapping file.

I've tried many things over the past several days, and can't seem to get it to work. I tried grouping the records and if 1 record was found, return that status. I've used decode, case, etc.

Here are a few examples of things I've tried. In the second example I get a 'not a single group group function' error.

Any thoughts?

select decode(i.active_status_id, 'OH', i.active_status_id, 'Ca', i.active_status_id,t.progress_status_id)
        from tasks t 
        LEFT OUTER JOIN Items i
                ON i.item_id = t.item_id
        where t.item_id = 10927815 and t.active_status_id = 'Ac' and t.active_status_id != 'Su' 
        group by i.active_status_id, t.progress_status_id;




select case                         
        when (count(*) = 1) then progress_status_id
        else 'St'
        end
        from 
        (select progress_status_id
                from tasks t 
                        where t.item_id = 10927815 and (t.active_status_id = 'Ac' and t.active_status_id != 'Su') group by t.progress_status_id)

perhaps somthing like this

SELECT 
  item_id
, CASE 
    WHEN active_status IN ('Canceled', 'On Hold') THEN active_status
    WHEN t_num = 0 THEN 'Completed'
    WHEN flag_all_active = 1 AND flag_all_not_started = 1 THEN 'Not Started'
    WHEN flag_all_active = 1 AND flag_all_completed = 1 THEN 'Completed'
    WHEN flag_all_active = 1 AND flag_all_on_hold = 1 THEN 'On Hold'
  ELSE 'Started'
  END
FROM
(
  SELECT 
      i.item_id
    , i.active_status
    , sum(CASE WHEN t.task_id is NULL THEN 0 ELSE 1 end ) as t_num
    , MIN( CASE t.active_status WHEN 'Ac' THEN 1 ELSE 0 END ) as flag_all_active 
    , MIN( CASE t.progress_status_id WHEN 'Not Starten' THEN 1 ELSE 0 END ) as flag_all_not_started
    , MIN( CASE t.progress_status_id WHEN 'Completed' THEN 1 ELSE 0 END ) as flag_all_completed
    , MIN( CASE t.progress_status_id WHEN 'On Hold' THEN 1 ELSE 0 END ) as flag_all_on_hold

  FROM 
    items i
    left outer join tasks t on (t.item_id = i.item_id )
  group by i.item_id
)
;

If you're using annotations you can use @Formula("sql query here") for your derived properties. See Hibernate formula docs for a (surprisingly brief) explanation.

Alternatively, since you're dealing with relatively large lists of items, it would be better to make the status calculations part of your initial query thus avoiding the database getting hammered by hundreds or thousands of requests. This is what will probably happen if you iterate over each item in the list.

I would recommend joining the status calculation to whatever query you are using to generate your list (presumably in a NamedQuery). This lets your database do all the heavy lifting without being slowed down by the network, which is what it is best at. The Hibernate docs give lots of helpful examples of queries you can try.

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