2017-11-02 1 views
0

MySQL (버전 : 5.6.29 및 10.1.28-MariaDB)에서 상위 n 개 (현재 2 개) 행을 가져 오려고합니다. SO 또는 다른 곳에서 간단한 예제를 보았습니다. (, example2) 문제는 내 쿼리가 더 복잡하고 잘 작동하지 않는 것입니다. (일부 필드를 간결하게 제거) 다이어그램 본MySQL이 상위 n 개의 레코드를 중첩 그룹으로 선택합니다.

는 I 테이블을 가지고

EER

각 purchase_item 수있을 어느 쿠폰 purchase_offer 또는 subscription_plan (하나가 유효하고 다른 두 null의). 이들 각각은 subscription_days > 0입니다.

가장 안쪽 SELECT는 예상대로 작동합니다. 두 번째 SELECT (같은 외부 선택을 제거 할 경우에도) 예상대로 작동하지 않습니다 purchase_rank 같은 동일한 customer_uuid 종종 같은 customer_uuid 기준으로 정렬하지 않는 경우 동일합니다.

아이디어가 있으십니까? I read ORDER BY가 중첩 된 쿼리에서 제대로 작동하지 않을 수 있습니다. 어떻게해야합니까? 또는 쿼리 최적화 프로그램이 이상한 일을하고 있습니까? 나는 CASE를 IF로 바꾸고 그 결과를 동일하게 시도했다. 어떤 도움을 크게 감상 할 수

SELECT 
    id, 
    uuid, 
    purchase_offer, 
    subscription_plan, 
    coupon, 
    customer_uuid, 
    payment_date, 
    subscription_days, 
FROM 
    (SELECT 
     id, 
      uuid, 
      purchase_offer, 
      subscription_plan, 
      coupon, 
      customer_uuid, 
      payment_date, 
      subscription_days, 
      @purchase_rank := CASE @current_customer 
       WHEN customer_uuid THEN @purchase_rank + 1 
       ELSE 1 
      END AS purchase_rank, 
      @current_customer:= customer_uuid AS current_customer 
    FROM 
     (SELECT 
      pi.id, 
      pi.uuid, 
      pi.purchase_offer, 
      pi.subscription_plan, 
      pi.coupon, 
      pi.customer_uuid, 
      p.payment_date, 
      IFNULL(po.subscription_days, IFNULL(sp.subscription_days, cpo.subscription_days)) AS subscription_days 
    FROM 
     purchase_item pi 
    JOIN purchase p ON p.id = pi.purchase 
    LEFT JOIN purchase_offer po ON pi.purchase_offer = po.id 
    LEFT JOIN subscription_plan sp ON pi.subscription_plan = sp.id 
    LEFT JOIN coupon cp ON pi.coupon = cp.id 
    LEFT JOIN purchase_offer cpo ON cp.purchase_offer = cpo.id 
    WHERE 
     p.status = 'COMPLETED' 
      AND pi.customer_uuid IS NOT NULL 
      AND p.payment_date IS NOT NULL 
      AND (po.subscription_days > 0 
      OR sp.subscription_days > 0 
      OR cpo.subscription_days > 0) 
    ORDER BY pi.customer_uuid , p.payment_date DESC) AS temp) 
AS pu 
WHERE 
    pu.purchase_rank <= 2 
ORDER BY pu.customer_uuid , pu.payment_date DESC 

: 다음은 코드입니다. 미리 감사드립니다.

답변

0

내 자신의 질문에 대답하기 : 나는 this을 발견했다. MariaDB뿐만 아니라 MySQL에서도 잘 작동하는 것으로 보입니다. 중첩 된 쿼리는 임시 테이블을 만드는 LIMIT <large number>이 필요합니다. 그래서 Cataklysm's answer은 부분적으로 정확하지만 더 작은 숫자에서는 작동하지 않습니다 (최소한 내 테스트에 따르지는 않음).

... 
ORDER BY pi.vehicle_uuid , p.payment_date DESC LIMIT 18446744073709551615) temp) pu 

여러분의 도움에 감사드립니다 : 여기에

코드의 일부를 수정됩니다.

0

MySql 쿼리의 이러한 종류의 제한 사항에 대해 문 끝에는 LIMIT 0, 2을 간단하게 추가 할 수 있습니다. 제한 문에 대한 자세한 내용은

확인 주시기 this documentation with realtime example.


편집 I 예를 들어

:

SELECT * FROM purchase 
ORDER BY payment_date ASC 
LIMIT n 
: 성명에서 처음 n 결과를 얻을 수 있습니다

그리고 그 반대의 경우 :

SELECT * FROM purchase 
ORDER BY payment_date DESC 
LIMIT n 

쿼리의 처음 n 개의 결과를 건너 뛰고 싶다면 LIMIT을 주어진 오프셋에서 시작할 수 있습니다. 예를 들어, 우리는 첫 번째 (10 개) 결과를 건너 뛰려면 :

SELECT * FROM purchase 
ORDER BY payment_date DESC 
LIMIT 10, n 
+0

감사합니다.하지만 실제로는 그렇지 않습니다. 'LIMIT'을 사용하면 그룹당 마지막 레코드가 아닌 모든 레코드가 제한됩니다 ('customer_uuid').내가 뭔가를 오해하지 않는다면? –

+0

@RokMirt 마지막 2? 당신 그룹의 첫 번째 결과가 필요하다고 생각 했나요? 그러나 문제가 아니어도 제한을 시작할 위치를 선택할 수 있기 때문에 결과가 얼마나 많은지 알거나 다른 ORDER BY로 작업해야합니다. – Cataklysim

+0

@Cataklysim 죄송합니다. 그렇습니다. 첫 번째 N을 의미합니다. 그러나, 내가하는대로 쿼리하면 모든 그룹 (그룹은'customer_uuid')의 첫 번째 N을 반환하지 않지만 모든 그룹에서 첫 번째 N을 가져옵니다. 예 : '고객 1'에서 3 번, '고객 2'에서 3 번, '고객 3'에서 3 번 구매했습니다. 구매는 동일한 순서로 수행되었습니다. 따라서 각 고객의 N = 2 구매를 원한다면 (가장 안쪽의 SELECT ... LIMIT 2) 6 번의 구매 대신 2 번만 'customer1'에서 반환합니다. 고객) –

관련 문제