2017-12-30 67 views
1

Sqliteで本を読んで、楽しい質問をテストすることにしました。顧客ごとの古い購入の列を追加して比較する

これは私に考えさせてくれました。

あなたは、以前のアイテムよりも低い価格で新しいアイテムを購入した連続購入者の数をどのように返すでしょうか?

  • そのすべてが同じテーブルに存在する必要はありません。

  • 関連するテーブル名:day:日付が買った、customerprice

は、これまでのところ私は、継続的な顧客を設置しているが、その前の購入のチェックを行うことはできません。

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

、ということありません自己結合を含める? –

+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 BY COUNT(*)> 1);を使用して、 'どこかで、**すべての**データベースの顧客をチェックする必要はありませんか? –

+1

私はしません。まず、それは必ずしも必要ではなく、2番目に、パフォーマンスを必ずしも向上させるものではありません。 –

+0

100万行がある場合は、クエリ内の継続的な顧客のみをフィルタリングする方が良いと思わないでしょうか? –

0

あなたは、CTEを使用することができます。これはあなたに実際の詳細を与えるでしょう。あなただけのカウントをしたい場合は、単にSELECT COUNT(*)で最終SELECT *を置き換える:

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; 

直前の購入と比較して見ている場合は、この代替:あなたは何が許可されている加入言わないとき

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 BY COUNT(*)> 1);を使用して、 'どこかで、**すべての**データベースの顧客をチェックする必要はありませんか? –

関連する問題