2014-08-29 4 views
3

제품 번호가 같지만 날짜가 다른 여러 행을 포함하는 데이터베이스 테이블의 가장 최근 항목을 선택하고 싶습니다. 이 특별한 경우 , 나는 테이블에 5 회 이상 발생 PRODUCT_NUMBER들에 의해 TKP_NOISE_MOTOR_RESULTS 표를 필터링 할, 그 부분 집합에서, 나는 각 prdocut 수SQL Oracle Query :이 쿼리를 최적화 할 수 있습니까?

에 대한 SAVEDATE 가장 최근 행을 검색 할

그런 쿼리를 만들었지 만 세 가지 하위 쿼리 T1, T2, T3가 있습니다. 나는 느낌이있다. 그것은 단지 두 개의 테이블만으로 수행 할 수 있으며 내부 조인은 필요하지 않다. 그러나 스크립트를 MySQL에서 Oracle로 변환하기가 어려웠 기 때문에이 스크립트를 만드는 데 많은 시간이 걸렸습니다.

하위 쿼리가 덜 필요하도록 다음 쿼리를 최적화 할 수 있습니까?

SELECT * FROM 
messfeld.TKP_NOISE_MOTOR_RESULTS T1 
JOIN 
(
    SELECT PRODUCT_NUMBER, COUNT(*) 
    FROM messfeld.TKP_NOISE_MOTOR_RESULTS 
    GROUP BY PRODUCT_NUMBER 
    HAVING COUNT(*)>5 
) T2 
ON T1.PRODUCT_NUMBER=T2.PRODUCT_NUMBER 
WHERE T1.SAVEDATE BETWEEN '27-AUG-14' AND '28-AUG-14' AND 
(T1.SAVEDATE, T1.PRODUCT_NUMBER) IN 
(
SELECT MAX(T3.SAVEDATE), T3.PRODUCT_NUMBER 
FROM messfeld.TKP_NOISE_MOTOR_RESULTS T3 
WHERE 
T2.PRODUCT_NUMBER=T3.PRODUCT_NUMBER 
GROUP BY PRODUCT_NUMBER 
); 
+0

몇 가지 샘플 데이터와 예상되는 결과를 보여줄 수 있습니까? 아니면 더 나은, [SQL 피들] (http://sqlfiddle.com/)을 만드시겠습니까? –

+0

흠, 두 가지 특정 날짜 사이의 레코드 만보고 계십니까? 또는 가장 최근의 날짜가 그 날짜 사이에있는 모든 레코드? –

+0

좋은 질문입니다. 생각 좀하자. –

답변

2

제품 번호와 날짜 만 원하는 경우 현재 방법을 상당히 단순하게 할 수 있습니다.

SELECT PRODUCT_NUMBER, MAX(SAVEDATE) 
FROM TKP_NOISE_MOTOR_RESULTS 
WHERE PRODUCT_NUMBER IN (
    SELECT PRODUCT_NUMBER 
    FROM TKP_NOISE_MOTOR_RESULTS 
    GROUP BY PRODUCT_NUMBER 
    HAVING COUNT(*)>5 
) 
GROUP BY PRODUCT_NUMBER; 

을하지만 다음 다른 열이있는 경우 다시 더 복잡하게 만들 필요가 : 당신은 당신이 당신이 필요한 것보다 한 번 더 테이블을 치는 것하고는 IN 절 조인 대체 할 수 의심한다.

당신은 테이블을 여러 번 누르거나 조인 할 필요 방지하기 위해 analytic functions를 사용할 수 있습니다

SELECT PRODUCT_NUMBER, SAVEDATE --, other columns 
FROM (
    SELECT T.*, 
    ROW_NUMBER() OVER (PARTITION BY T.PRODUCT_NUMBER 
     ORDER BY T.SAVEDATE DESC) AS RN, 
    COUNT(*) OVER (PARTITION BY T.PRODUCT_NUMBER) AS CNT 
    FROM TKP_NOISE_MOTOR_RESULTS T 
    WHERE T.SAVEDATE BETWEEN DATE '2014-08-27' AND DATE '2014-08-28' 
) 
WHERE CNT > 5 
AND RN = 1; 

내부 쿼리는 기본 테이블에서 모든 열을 취득하고, 분석 기능에 따라 pseudocolumns을 추가합니다. ROW_NUMBER()은 특정 제품의 각 행에 값을 할당하며 가장 최근 날짜를 숫자 1 (ORDER BY ... DESC 통해)로 지정합니다. 특히 넥타이가 있고 타이가 발생할 때 모든 행을 표시하려는 경우 RANK() 또는 DENSE_RANK()을 고려할 수도 있습니다. COUNT(*)은 각 제품의 행을 계산합니다.

그런 다음 외부 쿼리는 5보다 큰 수의 제품 만 포함하도록 필터를 필터링합니다. 그리고 가장 최근의 행만 첫 번째 행으로 가져옵니다.

SQL Fiddle 원래 검색어와 동일한 데이터에 대한 검색어입니다.

나는 또한 날짜 리터럴을 사용하도록 전환했습니다. 최소한 세션 NLS 설정에 의존하지 않고 명시적인 형식의 마스크를 사용하여 TO_DATE을 사용해야합니다. 또한 BETWEEN을 포함하여 (이 원본은 28 일 자정에 나타납니다. ..

WHERE T.SAVEDATE >= DATE '2014-08-27' 
    AND T.SAVEDATE < DATE '2014-08-28' 

또는 둘 다 일 다음 < DATE '2014-08-29'에서 모든 레코드를 포함하려는 경우 : 당신이 사용 할 수 있습니다. 나는 그들이 시간을 가지고 있다고 가정합니다. 그렇지 않으면 같은 날짜에 5 개의 레코드가 동일하게 보일 것이고, 어떤 것이 "최신"인지를 결정할 다른 방법이 필요할 것입니다.

+0

알렉스. 고마워. 귀하의 질의가 제 것보다 낫다고 보입니다. 저는 Oracle Database와 함께 회사에서 내 쿼리를 사용했으며 5 개의 결과를 얻었습니다. 귀하의 쿼리와 같은 날짜와 나는 8 결과를 얻을. 특별한 이유로, 차이점이 있습니다. 나는 조금씩 점검 할 것이지만, 어쨌든, 나는 당신의 질문을 사용할 것이다. 나는 특히 SQL에 초보자이기 때문에 많이 배울 수 있습니다. 다시 한 번 감사드립니다! –

+0

@Burkhard - 날짜 제한이 적용되어야하는 의견에 질문했습니다. 그 결과의 차이를 설명하겠습니까? 변경하는 것은 간단하지만 실제로 원하는 것인지 확실하지 않습니다. Thorsten 역시 세 번째 해석을하고 있으므로 선택 기준이 무엇인지 명확히하십시오. –

+1

@Alex Poole 이것은 정말 훌륭한 대답입니다. (내 것을 보지 않고서는 "준비 중"이었습니다. 그렇지 않은 경우 그냥 주석을 달았습니다.) 한 가지만, 행 번호 정렬에 DESC가 필요하지 않습니까? (가장 최근의 항목) –

2

상당히 오래된 오라클 버전을 사용하지 않는 한, COUNT()ROW_NUMBER()의 분석 양식을 사용하여 필자가 원하는 결과를 얻을 수 있습니다.

SELECT 
     * 
FROM (
     SELECT 
      TNMR.* 
      , COUNT(*) OVER (PARTITION BY TNMR.PRODUCT_NUMBER) AS CN 
      , ROW_NUMBER() OVER (PARTITION BY TNMR.PRODUCT_NUMBER 
           ORDER BY TNMR.SAVEDATE DESC) AS RN 
     FROM messfeld.TKP_NOISE_MOTOR_RESULTS TNMR 
    ) T1 
WHERE T1.CN >= 5 AND T1.RN = 1 
AND T1.SAVEDATE BETWEEN '27-AUG-14' AND '28-AUG-14' 
; 

그러나 정말 날짜 리터럴로 DD - 음 - 전년 동기 대비 권하고 싶지 않다, 나는 날짜 범위에 대한 BETWEEN을 사용하지 않을 대신 이것을 사용합니다 :이 시도

AND T1.SAVEDATE >= to_date('27-08-2014','dd-mmm-yyyy') 
AND T1.SAVEDATE < to_date('28-08-2014','dd-mmm-yyyy') + 1 -- 1 day added 

FOOTNOTE "select *"는 편의상 사용할 수있는 것으로, 위의 약어 만 사용하거나 세부 사항을 알 수 없기 때문에 사용됩니다. 선택 절을 완전히 지정하십시오.

+0

내부 질의의 다른 열과 평범한'*'을 결합 할 수 없으므로, 테이블의 별명을 지정하고 접두사를 붙이면된다. ORA-00923 –

+1

"꽤 오래된 Oracle 버전 *"- 창 함수 ("분석"함수라고도 함)는 Oracle 8i부터 사용할 수 있습니다. –

+0

@Alex (예 :'T. *, COUNT ... ' 풀 - 나는 평소 각주를 여기에 추가 할 것이다. 나는 당신이 맞다고 동의한다. 그러나 ... –

1

당신이

  • 8 월 27 일 또는 28 일에 적어도 하나 개의 기록을있는 개 이상 기록을 존재하는 모든 제품을 검색하는 것 같다.

이 중 해당 날짜 범위 내에있는 최신 레코드를 원합니다.

이미 5 개가 넘는 레코드가있는 모든 제품을 선택하고 케이스 구성을 사용하여 해당 날짜 범위에서 가장 최근의 저장 날짜를 결정하십시오.

select * 
from messfeld.tkp_noise_motor_results 
where (product_number, savedate) in 
(
    select 
    product_number, 
    max(case when to_char(savedate, 'dd-mm-yyyy') in ('27-08-2014', '28-08-2014') then savedate end) 
    from messfeld.tkp_noise_motor_results 
    group by product_number 
    having count(*) > 5 
    -- the next line is not really needed. Use it if you find it more readable 
    and max(case when to_char(savedate, 'dd-mm-yyyy') in ('27-08-2014', '28-08-2014') then savedate end) is not null 
);