如何有条件地联接并从联接表中获取数据?

时间:2019-01-07 13:56:56

标签: mysql sql ruby-on-rails ruby

我有两个表ProductProductNewsletter。一个产品可以有多个product_newsletters,因此,这在产品一侧是has_many关系,在product_newsletter一侧是belongs_to,带有product_id。表格看起来像这样:

products
id title... etc

product_newsletters
id product_id date

我想获取在一定日期范围内具有product_newsletter的产品,并从查询中找到的product_newsletter中选择日期。因此,如果一个产品有两个product_newsletter,其日期分别为11-03-2018、20-03-2018和04-04-2018,则查询日期介于01-03-2018和30-01-03-2018之间的用户将显示该产品两次,一次是2018年3月11日,另一次是20-03-2018。最初,我尝试使用子查询进行这种连接:

SELECT *
     , news.date AS newsletter_date 
  FROM products 
  JOIN 
     ( SELECT newsletter_products.* 
         FROM newsletter_products 
        WHERE newsletters.date BETWEEN '2018-01-03' AND '2018-01-20'
     ) news 
    ON  products.id = news.product_id

但是这种联接导致产品的ID与子查询中的新闻通讯相同,而不是product_id中的新闻,这与我从子查询中获得的期望相同。我在Rails和Mysql上使用ruby。我的想法是使用此查询的结果来简单地执行ruby products.group_by(&:newsletter_date),最后得到一个很好的哈希,将日期作为键,将乘积作为值,而无需对每个日期进行额外的查询或过滤,这是我目前的实施。

2 个答案:

答案 0 :(得分:3)

以下将为您提供预期的输出,

Product.joins(:product_newsletters).where(product_newsletters: { date: ['19-01-2013'.to_datetime..'19-02-2013'.to_datetime] })

如果2个product_newsletters对象在日期范围内并且都具有相同的product_id,则仍然对于上述查询,您将获得2 counts作为相同的产品ID。

答案 1 :(得分:2)

您应该这样编写查询:

SELECT p.*, n.date AS newsletter_date
FROM products p INNER JOIN 
     newsletter_products np
     ON p.id = n.product_id
WHERE np.date BETWEEN '2018-01-03' AND '2018-01-20';

注意:

  • 请勿使用select *。您将两次获得新闻通讯日期。
  • 子查询是不必要的,可能会妨碍优化。
  • 使用表别名,以便查询更易于编写和阅读。
  • 我不喜欢带有日期的between,但这就是您要做的逻辑。当date没有时间分量时,这是安全的。