0

I have the following two tables, one which contains a list of instructions and another which is basically an audit trail of state changes for the instruction. So for example an instruction has an initial status of "PENDING", and then it can be move to "Authorised" or "CANCELLED" or "IN Progress" etc., and we keep a trail of who moved it to what state, and when etc.

@Entity
@Table(name = "INSTRUCTION")
public class Instruction {

    @Id
    @Column(name = "ID", nullable = false, unique = true)
    public Long id;

    @Column(name = "ACCOUNT", nullable = false)
    public String account;

    @OneToMany(cascade = CascadeType.All, fetch = FetchType.EAGER)
    @JoinColumn(name = "INSTRUCTION_ID", referenceColumnName = "ID")
    @OrderBy("lastUpdated")
    private List<Audit> auditItems = new ArrayList<>();

    //Getters & Setters
}

.

@Entity
@Table(name = "AUDIT")
public class Audit {

    @Id
    @Column(name = "ID", nullable = false, unique = true)
    public Long id;

    @Column(name = "INSTRUCTION_STATUS", nullable = false)
    public InstructionStatus status;

    @Column(name = "LAST_UPDATED", nullable = false)
    public LocalDateTime lastUpdated;

    @Column(name = "LAST_UPDATED_BY", nullable = false)
    public String lastUpdatedBy;

    //Getters & Setters
}

I have to write a query that will return me all the "PENDING" instructions for a given account. So far I have worked out List<Instruction> findByAuditItemsStatusAndAccount(InstructionStatus status, String account) which will return me all the instructions that have a "PENDING" audit item in that list. However, this will return instructions that have other audit items too, for example ones with both "PENDING" and "AUTHORISE", which I don't want, because this has now moved to the authorised state and is no longer pending. What I want is to return only the instructions where the latest audit item is the provided status (in this example "PENDING"), but where I could also say pass it "AUTHORISED" and it would retrieve me ones where the latest audit item has a status of "AUTHORISED" and so on.

Is there a way to write the query to fetch me this? I know I could keep my query as is and then filter this using java, but I'd rather try and do it at the database level if possible.

For some clarification, see this sqlfiddle link. Basically I want a query that only returns the account H from that example. Is that possible?

1 Answer 1

2

For this problem you can use a subquery like :

SELECT INSTRUCTION.ACCOUNT, INSTRUCTION.ID FROM INSTRUCTION 
INNER JOIN INSTRUCTION_AUDIT ON INSTRUCTION.ID = INSTRUCTION_AUDIT.INSTRUCTION_ID
WHERE INSTRUCTION.ID not in (SELECT INSTRUCTION_ID
                             FROM INSTRUCTION_AUDIT 
                             WHERE STATUS !='PENDING');

You can test the query in SQL Fiddle.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.