【问题标题】:Add columns of old purchases per customer to compare them添加每个客户的旧购买列以进行比较
【发布时间】:2018-06-10 16:31:44
【问题描述】:

阅读一本关于 Sqlite 的书,并决定测试某些查询以获得乐趣。

这个让我思考。

你将如何返回以低于之前商品的价格购买新商品的连续购买者的数量?

  • 不需要所有连接都在同一个表中。

  • 相关表名:day:购买日期,customerprice

到目前为止,我已经找到了连续的客户,但无法检查他们之前的购买情况。

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

认为通过将每个客户的购买添加到彼此相邻的列中,由date_bought 订购可能是进行实际“每个连续客户”检查的唯一方法。

为了重现性,你可以使用这个:

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');

【问题讨论】:

  • 当您说不允许加入时,是否包括自加入?
  • 我没有这么说,我说他们只是在同一张桌子上。自联接可能是解决问题的途径,但很难做到正确

标签: sql database sqlite subquery


【解决方案1】:

您可以使用 CTE。这将为您提供实际的详细信息。如果您只想要计数,只需将最后的 SELECT * 替换为 SELECT COUNT(*)

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);

【讨论】:

  • 虽然名称正确,但对应名称的旧价格和最后价格不正确,请查看
  • 由于尚不完全清楚您是要在最后一个还是之前的任何一个之前购买,我假设该客户之前的任何购买。从这个意义上说,它是正确的。你能提供你预期的正确结果吗?我会相应地更新查询。
  • 您如何通过选择仅针对已经持续使用的客户执行您所写的操作来提高速度?例如使用我的选择语句:SELECT * FROM (SELECT * FROM ORDERS GROUP BY CUSTOMER HAVING COUNT(*)&gt;1); somewhere,所以它不必检查**所有**数据库中的客户?
  • “所以它不必检查**所有**数据库中的客户?”:必须检查所有行(无论是直接还是通过相应的索引)的一种或另一种方式针对某些条件,否则您将如何获得有效的结果? (顺便说一句,你的外部select 是多余的。)你认为你的select 会神奇地跳过行来得出正确的答案吗?在您得到正确的结果之后进行优化。先解决这个问题,然后再考虑微调你的方法。您的陈述错误地假设您的select 以某种方式使整个工作变得更容易。好吧,它没有!
  • 实际上,我的选择是一个示例,让您了解我处理大量数据集的观点,其中大多数是一次性购买者。您将如何过滤掉这些以更快地完成此过程。
【解决方案2】:

我的自我加入方法是这样的。

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

【讨论】:

  • 您如何通过选择仅针对已经持续的客户执行您所写的操作来提高速度?例如使用我的选择语句:SELECT * FROM (SELECT * FROM ORDERS GROUP BY CUSTOMER HAVING COUNT(*)&gt;1); somewhere,所以它不必检查所有数据库中的客户?
  • 我不会。首先,它没有必要,其次,它不一定会提高性能。
  • 如果您有 100 万行,您不认为只过滤查询中的连续客户会更好吗?
【解决方案3】:

如果您只想要计数而不关心特定客户是谁,那么获取多次订购同一商品的客户计数的一种方法是使用带有 exists 谓词的相关子查询:

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
    );

这会返回不同客户的数量,这些客户在前一天存在同一商品且价格较高的行。

如果我理解你的问题,我想这就是你想要的。

【讨论】:

  • 您如何通过选择仅针对已经持续使用的客户执行您所写的操作来提高速度?例如在某处使用我的选择语句:SELECT * FROM (SELECT * FROM ORDERS GROUP BY CUSTOMER HAVING COUNT(*)&gt;1);,所以它不必检查数据库中的所有客户?
  • 我不确定我是否可以让它更快(如果这确实是一个问题),因为任何解决此问题的方法都需要检查一组与另一组,以便找到匹配客户和项目以及不同的日期和价格属性。给定适当的索引,这应该与任何其他解决方案一样快地执行。如果您有一个非常大的数据集,我想您可以对其进行预处理以删除没有重复订购相同商品的客户的行,但在正常情况下,这可能是过早优化的情况。
  • 这正是我所说的。更像是在你这样做之前进行过滤。考虑到其中大多数是一次性购买者的庞大数据集,我将如何预处理?
  • 我会按照您的建议先过滤掉非重复客户,然后使用剩余的集合作为查询源。可能是这样的:sqlfiddle.com/#!6/9eecb7db59d16c80417c72d1e1f4fbf1/17371
猜你喜欢
  • 1970-01-01
  • 2019-04-16
  • 2023-03-24
  • 2020-07-09
  • 1970-01-01
  • 2022-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多