2016-07-29 5 views
0

'리더'객체의 상태 기록을 포함하는 간단한 테이블이 있습니다. 상태는 ACTIVE 또는 INACTIVE 일 수 있습니다. 이제는 주어진 기간 동안 활성화 된 모든 독자를 선택하는 쿼리를 원합니다. 다음 이미지는 내가 의미하는 바를 보여준다 : 녹색의 'lifeline'을 가진 '독자'는 표시된 기간에 ACTIVE였다. 그래서 그들은 질의에 반환 될 것이다. 이 (예를 들어 단지 상기 이미지와 일치하지 않음)처럼주어진 기간에 상태 기록 테이블의 활성 상태를 선택하십시오.

enter image description here

tabel ReaderActivity 본다 :

물론
reader_id | state | timestamp 
1  | ACTIVE | 1467331201089 
2  | ACTIVE | 1467332454545 
1  | INACTIVE | 1467348875254 
3  | ACTIVE | 1467350416546 
1  | ACTIVE | 1467351871123 
2  | INACTIVE | 1467352111545 

가되는이 reader_id가 맵핑하는 Reader 엔티티있다.

이 문제에 대한 JPA 쿼리가 필요하지만 그 기간 내에 이미 '상승 에지'가없는 결과 (INACTIVE에서 ACTIVE로 상태가 변경됨)가있는 독자가 포함 된 문제가 있습니다. 우리가 조사하는 기간). 모든 상승 에지를 가진 선택

  • 첫째 :

    내가 너무 기본적으로 쿼리의 일부를 참조하십시오. 이것은 간단합니다. SELECT DISTINCT a.reader FROM ReaderActivity a WHERE a.timestamp >= :startTimestamp AND a.timestamp < :endTimestamp AND a.state = 'ACTIVE'

  • 둘째, 모든 독자 위에 목록에 추가해야합니다. 모든 독자는 기간 시작 전에 마지막 상태 인 ACTIVE를가집니다. 이것은 내가 제대로하지 않는 것입니다 : SELECT DISTINCT a.reader FROM ReaderActivity a WHERE a.timestamp >= :startTimestamp AND a.timestamp < :endTimestamp AND a.state = 'ACTIVE' or (SELECT aa.reader FROM ReaderActivity aa where aa.reader = a.reader AND aa.timestamp < :startTimestamp AND aa.state = 'ACTIVE' GROUP BY aa.reader ORDER BY max(aa.timestamp)) != null

이것은 또한 반환 빨간색 하위 쿼리에서 AND aa.state = 'ACTIVE'와 함께, 우리는 이미 필터링 때문에 위의 이미지에서 독자를 표시 : 나는 (주먹 쿼리로 결합) 시도 모든 ACTIVE 상태이므로 마지막 ACTIVE 상태가됩니다. 시작일 이전에 마지막 상태를 선택하고 이후에 활성 상태인지 확인해야합니다. 그러나 어떻게?

아무도 올바른 방법으로 나를 데려 갈 수 있습니까? 미리 감사드립니다.

답변

1

검색어의 첫 번째 부분은 원하는 기간 동안 상태가 활성으로 변경된 기록을 다시 가져옵니다. 쿼리의 두 번째 부분은 약간의 정제가 필요합니다.

"startTimeStamp"가 발생할 때까지 모든 reader_id의 최신 상태 변경 사항을 가져와야합니다. 그런 다음 그 당시에 "ACTIVE (활성)"로 나열된 것을 선택하기 만하면됩니다. 이 쿼리는 지정된 기간의 시작에서 활성화되었던 모든 [reader_id]의를 반환합니다

Select a.reader_id 
From ReaderActivity a 
Where a.timeStamp in 
( 
    Select max(b.timeStamp) 
    From ReaderActivity b 
    Where b.timestamp < :startTimeStamp 
    And b.reader_id = a.reader_id 
    Group By b.reader_id 
) 
and a.state = "ACTIVE" 

뭔가 같은 ....이것을 원래 쿼리의 where 절에서 실행하거나 UNION을 사용하여 쿼리 끝에 추가하고 Select Distinct (reader_id)를 실행하면됩니다.

테이블에서 그룹의 최대 값을 선택하는 것은 항상 저에게 이상합니다. 그러나이 쿼리가 도움이되기를 바랍니다.

+0

고맙습니다, 루크! 나는 ...을 사용할 수있는 가능성을 놓쳤다.() ... [+1] - 나의 전체 질의는 이제 다음과 같다 :'SELECT DISTINCT a.reader From ReaderActivity a where a.timestamp> = : startTs AND a.timestamp <: endTs AND a.state = 'ACTIVE'OR (a.timestamp IN (SELECT MAX (b.timestamp) FROM ReaderActivity b WHERE b.timestamp <: startTs GROUP BY b.reader) AND a.state = 'ACTIVE') '- 한 가지 질문 : 마지막에 '국가'를 대괄호로 묶은 이유는 무엇입니까 ('... and a. [state] = ...')? – badera

+1

중요한 힌트를 해결할 수 없습니까? *이 쿼리에주의해야 할 유일한 이유는 특정 이유로 reader_id 'a'가 밀리 초 단위로 "INACTIVE"로 설정된 경우 ... 추가하여 ... 'where b.reader_id = a.reader_id'는 하위 선택의 where 절에 있습니까? – badera

+0

첫 번째 질문에 대한 답변으로 국가에서 대괄호를 제거해도 검색어가 변경되지 않으며 둘 중 아무 것도 입력하지 않습니다. 열이 공백으로 분리 된 단어로 구성되어있을 때 하나의 열을 그룹화하여 유지하려면 열 주위에 대괄호가 필요합니다. 웬일인지 나는 2 개의 단어로서 상태를 읽는다 (확실하지 않은 방법). 두 번째 질문에 대한 대답으로 예! a.reader_id = b.reader_id에 where 필터를 추가하면 'INACTIVE'레코드를 다시 가져올 수 없습니다. 이를 반영하도록 쿼리를 변경하겠습니다. @ 바데라 – Luke

1

이 쿼리를 수행해야합니다

SELECT r.reader_id, r.timestamp 
FROM ReaderActivity r 
WHERE r.timestamp>=:start AND 
     r.timestamp<=:stop AND 
     r.state='ACTIVE' 

UNION ALL 

SELECT r1.reader_id, r1.timestamp 
FROM ReaderActivity r1 
LEFT JOIN ReaderActivity r2 ON (r2.reader_id = r1.reader_id AND 
           r2.timestamp<:start AND 
           r2.timestamp>r1.timestamp) 
WHERE r1.timestamp<:start AND 
     r1.state='ACTIVE' AND 
     r2.id IS NULL 

연합의 fisrt 부분은 시간 내에 활성화와 UNION의 두 번째 부분은 시간 전에 활성화 만 독자를 선택하는 독자를 선택합니다.

쿼리를 테스트하지 않았으므로 약간 조정해야 할 수도 있습니다.

+0

Victorqedu! [+1] 죄송합니다. 귀하의 답변에 '동의 함'으로 표시하지 않았습니다. 그러나 루크의 한 사람은 조금 더 행복합니다. – badera

+0

타임 스탬프로 선택하는 것이 안전하지 않습니다 - 누가가 대답의 마지막에 언급 한 것처럼. – Victorqedu

+0

하위 쿼리의 필터가 상위 선택의 항목으로 제한되는 이유는 무엇입니까? 두 명의 독자가 같은 타임 스탬프로 여러 항목을 생성한다는 것은 기술적으로 불가능합니다. 나는이 답변을 직접 토론하는 것이 더 좋을 것이라고 생각합니다! – badera