【问题标题】:how to select/find the table data along with the latest associated (many to many) data如何选择/查找表数据以及最新的关联(多对多)数据
【发布时间】:2012-01-11 08:34:51
【问题描述】:

我的表格中有以下关系

item.rb

has_one :item_shipping_detail

item_shipping_detail.rb

belongs_to  :item
has_many :shipping_statuses

status.rb

belongs_to  :item_shipping_detail

例如。数据

项目

id   title     city      state             country
 1   Title1    Nagpur    Maharashtra       India

item_shipping_details

id   item_id    price     description
 1   1          10        Electronic

状态

id   item_shipping_detail_id    status_city     status_state   status_country  created_at 
 1   1                           Mumbai         Maharashtra    India           2012-01-09 07:58:16
 2   1                           Akola          Maharashtra    India           2012-01-10 07:58:16
 3   1                           Nagpur         Maharashtra    India           2012-01-11 07:58:16

我想要使用单个查询得到以下结果(item、item_shipping_details、status (LATEST or MAX)

id title city     state         country  price  description  status_city  status_state    status_country
 1 Title1 Nagpur  Maharashtra    India    10    Electronic   Nagpur       Maharashtra    India

JYI:- 我使用的是 Rails 2.3.8

【问题讨论】:

  • 你的 statuses 表中的三个 status_city 列实际上分别是 status_city、status_state 和 status_country 吗?
  • 是的,马克这只是错字,但我编辑了问题。
  • 您使用的是哪个版本的 PostgreSQL?
  • 好吧,这是我的错,但是有什么方法可以为此构建查询吗?
  • Gary 的回答绝对值得一试。

标签: sql ruby-on-rails postgresql rails-postgresql


【解决方案1】:

试试:

select i.id,
       i.title,
       i.city,
       i.state,
       i.country,
       d.price,
       d.description,
       s.status_city,
       s.status_state,
       s.status_country
from items i
left join item_shipping_details d on i.id = d.item_id
left join 
   (select s1.* from statuses s1
     where not exists 
           (select * from statuses s2
        where 
                s2.item_shipping_detail_id = s1.item_shipping_detail_id 
                and s2.created_at> s1.created_at) )  s
on d.id = s.item_shipping_detail_id

子选择上的 where 子句过滤掉任何有更新记录的记录。这实际上与 Mark Ba​​nnister 的查询相同(在我的 Postgresql 9.1 数据库上运行良好),但不使用分区函数。

它可能没有分区函数那么有效,所以如果你能弄清楚为什么你的函数没有运行(可能是 8.4 兼容性设置或其他什么?)我会去他的查询。

【讨论】:

  • +1 我现在已经删除了我的答案,因为 Salil 透露select version(); 语句的结果是“i386-redhat-linux-gnu 上的 PostgreSQL 8.3.8,由 GCC gcc ( GCC)4.3.2 20081105(红帽 4.3.2-7)“。换句话说,他正在运行一个不支持窗口函数的 Postgres 版本(来自 cmets 对此问题的回答:stackoverflow.com/questions/1872705/…)。
  • 我也支持你,但这太慢了,有没有什么有效的方法可以让我拥有大量数据。
  • 为了解决性能问题,我们需要更多信息。每张表有多少行?哪些字段被索引?您是查询整个表格还是单个项目?
  • 实际上,这可能值得作为一个单独的问题提出,以便更多人看到。
【解决方案2】:

使用 DISTINCT ON,一个 postgresql 扩展:

select distinct on(i.id, d.id)
   i.id,
   i.title,
   i.city,
   i.state,
   i.country,
   d.price,
   d.description,
   s.status_city,
   s.status_state,
   s.status_country
from items i
left join item_shipping_details d on i.id = d.item_id
left join statuses s on s.item_shipping_detail_id = d.id
order by i.id, d.id, s.created_at desc

还要考虑标准语法:

select * from (
select i.id,
   i.title,
   i.city,
   i.state,
   i.country,
   d.price,
   d.description,
   s.status_city,
   s.status_state,
   s.status_country,
   row_number() over(partition by d.id, i.id order by s.created_at desc) as rn
from items i
left join item_shipping_details d on i.id = d.item_id
left join statuses s on s.item_shipping_detail_id = d.id
) tab where tab.rn = 1

【讨论】:

  • 显示 OP 使用的是没有窗口功能的 8.3.8。
  • "PostgreSQL 版本是 9.1.2 – Salil 1 月 19 日 6:02" 。此外,DISTINCT ON 版本至少与 7.1 相关
  • 我只评论了窗口函数,而不是 DISTINCT ON :) 重新审视版本,检查对 Gary 回答的第一条评论。他可能最初声明 9.1.2,但随后他在对现已删除的答案的评论中改变了主意...
【解决方案3】:

您必须在状态中包含“某些内容”,以便您可以选择最新状态,例如到达日期左右。在您提供额外的专栏之前,无法回答您的问题。

【讨论】:

  • 查看我的已编辑问题,我在状态表中添加了“created_at”列。
【解决方案4】:

事实证明,您使用的是8.3.8(来自对已删除答案的评论),您不能使用row_number()。这意味着我倾向于加入聚合子查询以确定哪条记录是最新的。比如……

SELECT
   i.id,
   i.title,
   i.city,
   i.state,
   i.country,
   d.price,
   d.description,
   s.status_city,
   s.status_state,
   s.status_country
FROM
  items                    i
LEFT JOIN
  item_shipping_details    d
    ON i.id = d.item_id
LEFT JOIN
  (SELECT item_shipping_detail_id, MAX(created_at) AS created_at FROM statuses GROUP BY item_shipping_detail_id)   lookup
    ON lookup.item_shipping_detail_id = d.id
LEFT JOIN
  statuses                 s
    ON  s.item_shipping_detail_id = lookup.item_shipping_detail_id
    AND s.created_at              = lookup.created_at

注意:为了优化子查询和连接,statuses 表确实需要适当的索引; (item_shipping_detail_id, created_at)

如果您在 (item_shipping_detail_id, id) 上有索引,并且您可以保证较高的 id总是意味着记录比 id 较低的记录更新,您可以在我的查询中用id 替换出现的created_at

【讨论】:

    【解决方案5】:

    试试这个

    select distinct on(i.id, d.id)
       i.id,
       i.title,
       i.city,
       i.state,
       i.country,
       d.price,
       d.description,
       s.status_city,
       s.status_state,
       s.status_country
    from items i
    left join item_shipping_details d on i.id = d.item_id
    left join statuses s on s.item_shipping_detail_id = d.id
    where s.id = (select Max(id) as id from statuses where item_shipping_detail_id = d.id)
    order by i.id, d.id desc
    

    【讨论】:

    • 根据我的经验,这种相关子查询方法在逻辑上与加入不相关子查询的方法相同,但速度较慢。
    猜你喜欢
    • 2021-09-25
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-11
    相关资源
    最近更新 更多