我有一个users
表,它通过外键user_purchases
与user_id
表有一对多的关系。也就是说,每个用户可以进行多次购买(或者可能没有购买,在这种情况下,他在user_purchases表中没有条目)。
user_purchases
此处只有一个其他感兴趣的字段,即purchase_date
。
我正在尝试编写一个Sequel ORM语句,该语句将返回包含以下列的数据集:
因此,未完成至少2次购买的用户将不会出现在此数据集中。写这篇续集声明的最佳方式是什么?
请注意我正在寻找一个包含> = 2次购买的所有用户的数据集
谢谢!
以下是我为了获取用户及其首次购买日期而写的类似声明(与第二次购买日期相反,我在当前帖子中寻求帮助):
DB[:users].join(:user_purchases, :user_id => :id)
.select{[:user_id, min(:purchase_date)]}
.group(:user_id)
答案 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_group
和select_more
:https://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"