2017-12-30 103 views
1

Sqlite에서 책을 읽고 재미있는 질문을 테스트하기로 결정했습니다.비교할 고객 당 구 구매 열 추가

이 사람은 저를 생각합니다.

이전 항목보다 저렴한 가격으로 새 항목을 구입 한 연속 구매자의 수를 어떻게 반환 하시겠습니까?

  • 동일한 테이블에 모든 조인이 필요하지 않습니다.

  • 관련 테이블 이름 : day : 날짜가 구입, customer, price

지금까지 내가 연속 고객을 찾았지만 이전 구매 확인을 할 수 없습니다.

SELECT * FROM (SELECT * FROM ORDERS GROUP BY CUSTOMER HAVING COUNT(*)>1); 

date_bought에 의해 주문, 서로 옆에 열의 각 고객의 구매를 추가하여 아마도 '지속적인 고객 당'실제를 할 수있는 유일한 방법이라고 생각 확인합니다.

reproducibillity 위해 당신은이를 사용할 수 있습니다

CREATE TABLE orders (
    day DATE, 
    price FLOAT 
    item char 
    customer char 
); 

INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-2 day'), 0.5,'food','Jenny'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-23 day'), 1,'food','Jenny'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-1 day'), 11,'food','Betty'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-22 day'), 7,'food','Betty'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-3 day'), 8,'food','Katy'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-4 day'), 10,'food','Mary'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-23 day'), 1,'food','Mary'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-1 day'), 2,'food','Anna'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-2 day'), 12,'food','Anna'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-3 day'), 8,'food','Anna'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-4 day'), 10,'food','Lisa'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-5 day'), 5,'food','Lisa'); 
INSERT INTO orders(day, price,item,customer) VALUES(date('now', 'localtime', '-8 day'), 12,'food','Jenny'); 
+1

:

with xxx(day,price,item,customer,previous_price,previous_date) as ( select *,null,null from orders group by customer having min(day) union all select o.day,o.price,o.item,o.customer,x.price,x.day from orders o join xxx x using(customer) where o.price < x.price and o.day > x.day ) select * from xxx where previous_price is not null; 

비교에서 바로 이전의 구매, 다음이 대안을 찾고 있다면 자체 조인을 포함할까요? –

+0

나는 그것을 말하지 않았다, 나는 그들이 같은 테이블에 있다고 말했다. 자체 조인은 아마도 해결책의 길일 수 있지만 올바르게 수행하기는 어려웠습니다. –

답변

0

당신은 단지 수를 원하는 특정 고객이 더 후 같은 항목을 주문한 고객의 수를 얻을 수있는 하나 개의 방법이 누군지 상관하지 않는 경우 이 같은 항목과 함께 행이 존재하는 고유 한 고객의 수를 반환

select count(distinct customer) 
from orders o1 
where exists (
    select customer 
    from orders o2 
    where o1.customer = o2.customer and 
      o1.item = o2.item and 
      o1.day > o2.day and 
      o1.price < o2.price 
    ); 

: 한 번 이상, 그리고 나중에 낮은 가격의 exists 술어와 상관 하위 쿼리를 사용하는 것입니다 일찍 더 높은 가격 일.

내가 귀하의 질문을 이해한다면 나는 이것이 당신이 원하는 것이라고 생각합니다.

+0

이미 지속적인 고객에게만 쓴 것을 어떻게하면 빨리 할 수 ​​있습니까?예를 들어 SELECT select * FROM (SELECT * FROM ORDERS GROUP BY CUSTOMER HAVING COUNT (*)> 1); 어딘가에 ** 모든 ** ** 데이터베이스의 고객을 확인할 필요가 없습니다. –

+0

나는이 문제에 대한 해결책이 고객과 항목 및 날짜와 가격 속성이 일치하는 제품을 찾기 위해 한 세트를 검사하는 것과 관련하여 (고객이 실제로 문제가되는 경우) 더 빨리 만들 수 있는지 잘 모르겠다. . 적절한 인덱스가 주어지면 다른 솔루션보다 빠르게 실행되어야합니다. 매우 큰 데이터 세트를 가지고있는 경우 동일한 항목을 반복적으로 주문하지 않은 고객과 행을 제거하기 위해 사전 처리 할 수 ​​있지만 일반적으로 조기 최적화의 경우 일 수 있습니다. – jpw

+0

이것은 정확히 내가 말한 것입니다. 당신이하기 전에 필터링하는 것보다 훨씬 큽니다. 그들 대부분이 한 번 거대한 데이터 세트를 어떻게 전처리하면 좋을까요? –

0

내 자체 조인 방식은 다음과 같습니다.

select your field 
from orders o1 join orders o2 on o1.customer = o2.customer 

where o2.price < o1.price 
and o1.day = (select max(day) 
from orders 
where day < o2.day 
and customer = o2.customer) 

their previous item은 최근 주문한 항목을 나타냅니다. their previous item는 이전의 순서를 의미하는 경우에 서브 쿼리를 대체 할 수

and o1.day < o2.day 
+0

당신은 이미 지속적인 고객에게만 쓴 것을 어떻게하면 빨리 할 수 ​​있습니까? 예를 들어 SELECT select * FROM (SELECT * FROM ORDERS GROUP BY CUSTOMER HAVING COUNT (*)> 1); '어딘가에 있으므로 ** 모든 ** 데이터베이스의 고객을 확인할 필요는 없습니다. –

+1

나는 그렇지 않다. 첫째, 반드시 필요한 것은 아니며 둘째로 성능을 반드시 향상시킬 수는 없습니다. –

+0

1 백만 행이있는 경우 쿼리의 연속 고객 만 필터링하는 것이 더 좋지 않다고 생각하십니까? –

0

당신은 CTE를 사용할 수 있습니다. 이것은 당신에게 실제 세부 사항을 줄 것이다. 당신은 카운트가 단순히 교체하려는 경우 최종 SELECT *SELECT COUNT(*)와 : 그 않는, 더 허용 조인 말할 때

with xxx(day,price,item,customer,previous_price,previous_date) as (
    select *,null,null from orders 
    union all 
    select o.day,o.price,o.item,o.customer,x.price,x.day 
    from orders o join xxx x using(customer) 
    where o.price < x.price 
     and o.day > x.day 
) 
    select * from xxx group by customer having max(previous_date); 
+0

이름이 정확하더라도 해당 이름의 이전 가격과 마지막 가격은 사실이 아닙니다. –

+0

마지막 구매 직전과 이전 구매를 모두 원하는지 확실하지 않으므로 이전 그 고객이 구입. 그런 의미에서 올바른 것입니다. 예상 한 정확한 결과를 제공 할 수 있습니까? 그에 따라 쿼리를 업데이트 할 것입니다. – tonypdmtr

+0

당신은 이미 지속적인 고객들에게만 쓴 것을 어떻게하면 빨리 할 수 ​​있을까요? 예를 들어 SELECT select * FROM (SELECT * FROM ORDERS GROUP BY CUSTOMER HAVING COUNT (*)> 1); '어딘가에 있으므로 ** 모든 ** 데이터베이스의 고객을 확인할 필요는 없습니다. –