续集 - 如何构建此查询?

时间:2012-11-02 16:50:23

标签: ruby-on-rails ruby sequel

我有一个users表,它通过外键user_purchasesuser_id表有一对多的关系。也就是说,每个用户可以进行多次购买(或者可能没有购买,在这种情况下,他在user_purchases表中没有条目)。

user_purchases此处只有一个其他感兴趣的字段,即purchase_date

我正在尝试编写一个Sequel ORM语句,该语句将返回包含以下列的数据集:

  • USER_ID
  • 用户第二次购买的日期(如果存在)

因此,未完成至少2次购买的用户将不会出现在此数据集中。写这篇续集声明的最佳方式是什么?

请注意我正在寻找一个包含> = 2次购买的所有用户的数据集

谢谢!

编辑清晰度

以下是我为了获取用户及其首次购买日期而写的类似声明(与第二次购买日期相反,我在当前帖子中寻求帮助):

   DB[:users].join(:user_purchases, :user_id => :id)
              .select{[:user_id, min(:purchase_date)]}
              .group(:user_id)

3 个答案:

答案 0 :(得分:2)

您似乎并不担心日期,只是计算如此

DB[:user_purchases].group_and_count(:user_id).having(:count > 1).all

会返回一个user_ids列表,并计算(购买次数)>> = 2的内容。

[{:count=>2, :user_id=>1}, {:count=>7, :user_id=>2}, {:count=>2, :user_id=>3}, ...]

如果你想让用户得到它,那么使用Sequel最简单的方法可能就是只提取user_id列表并将其反馈给另一个查询:

DB[:users].where(:id => DB[:user_purchases].group_and_count(:user_id).
    having(:count > 1).all.map{|row| row[:user_id]}).all

修改

我觉得应该有一个更简洁的方式然后我看到这个答案(从续集作者杰里米埃文斯)到另一个问题使用select_groupselect_morehttps://stackoverflow.com/a/10886982/131226

这应该在没有子选择的情况下完成:

DB[:users].
  left_join(:user_purchases, :user_id=>:id).
  select_group(:id).
  select_more{count(:purchase_date).as(:purchase_count)}.
  having(:purchase_count > 1)

它生成此SQL

SELECT `id`, count(`purchase_date`) AS 'purchase_count' 
FROM `users` LEFT JOIN `user_purchases` 
ON (`user_purchases`.`user_id` = `users`.`id`) 
GROUP BY `id` HAVING (`purchase_count` > 1)"

答案 1 :(得分:0)

通常,这可能是您需要的SQL查询:

SELECT u.id, up1.purchase_date FROM users u
LEFT JOIN user_purchases up1 ON u.id = up1.user_id
LEFT JOIN user_purchases up2 ON u.id = up2.user_id AND up2.purchase_date < up1.purchase_date
GROUP BY u.id, up1.purchase_date
HAVING COUNT(up2.purchase_date) = 1;

如果你没有得到更好的答案,请尝试将其转换为续集。

答案 2 :(得分:0)

如果您在查询中执行order_by(:purchase_date),则用户第二次购买的日期将是检索到的第二行。

要访问该内容,请执行limit(2)将查询约束为两个结果,然后选择[-1](或last)。因此,如果您不使用模型并且仅使用数据集,并且知道您感兴趣的user_id,那么您的(未经测试的)查询将是:

DB[:user_purchases].where(:user_id => user_id).order_by(:user_purchases__purchase_date).limit(2)[-1]

以下是Sequel控制台的一些输出:

DB[:user_purchases].where(:user_id => 1).order_by(:purchase_date).limit(2).sql
=> "SELECT * FROM user_purchases WHERE (user_id = 1) ORDER BY purchase_date LIMIT 2"

添加适当的select子句:

.select(:user_id, :purchase_date)

你应该完成:

DB[:user_purchases].select(:user_id, :purchase_date).where(:user_id => 1).order_by(:purchase_date).limit(2).sql
=> "SELECT user_id, purchase_date FROM user_purchases WHERE (user_id = 1) ORDER BY purchase_date LIMIT 2"