【问题标题】:Returning the first X records in a postgresql query with a unique field返回具有唯一字段的 postgresql 查询中的前 X 条记录
【发布时间】:2014-02-21 01:02:59
【问题描述】:

好的,所以我在这里有一点学习时间,在弄清楚 A 让它工作的方法之后,我很好奇是否有更多 postgres 经验的人可以帮助我找出一种方法来做到这一点,而无需在场景栏杆后面做很多事情(或对我要获取的每个项目进行一次查询)......现在解释一下:

假设我有 1000 条记录,我们将它们称为“实例”,在具有这些字段的数据库中:

id
user_id
other_id

我想创建一个我可以调用的方法,它会拉入 10 个实例,这些实例都有一个唯一的 other_id 字段,用简单的英语(我意识到这行不通:)):

Select * from instances where user_id = 3 and other_id is unique limit 10

因此,我希望能够在这 10 个实例上运行映射函数并返回类似 [1 ,2,3,4,5,6,7,8,9,10]。

理论上,我目前可能可以做以下两件事之一,尽管我试图避免它们:

  1. 存储一个 id 数组并进行单独调用,确保下一个调用显示“不在此数组中”。这里的问题是我正在执行 10 个单独的数据库查询。

  2. 提取一大块,比如说 50 个实例,并在 ruby​​-land 中对它们进行排序以找到 10 个唯一的实例。这不允许我利用数据库中已经完成的任何优化,而且我还会冒着对没有 10 个唯一 other_id 的 50 个项目进行查询的风险,除非我做了另一个查询。

无论如何,希望有人能告诉我我忽略了一个简单的选项 :) 我知道这是在真正需要之前进行某种优化,但是这个函数将会被运行并且一遍又一遍,所以我认为现在这不是浪费时间。

为了记录,我使用的是 Ruby 1.9.3、Rails 3.2.13 和 Postgresql (Heroku)

谢谢!

编辑:只是想举一个在技术上确实有效的函数示例(并且是上面的第 1 位)

def getInstances(limit, user)
  out_of_instances = false
  available = []
  other_ids = [-1] # added -1 to avoid submitting a NULL query

  until other_ids.length == limit || out_of_instances == true

    instance = Instance.where("user_id IS ? AND other_id <> ALL (ARRAY[?])", user.id, other_ids).limit(1)

    if instance != []
      available << instance.first
      other_ids << instance.first.other_id
    else
      out_of_instances = true
    end
  end
end

你会跑:

getInstances(10, current_user)

虽然这可行,但并不理想,因为每次调用它都会导致 10 个单独的查询:(

【问题讨论】:

  • 你可以GROUP BY other_id,不是吗?
  • 是的!我正在考虑这个问题,但我不确定您是否可以获得特定数量的组?这是一个问题,而不是陈述:) 我真的不确定是否像这样:“Select * from instances where user_id = 3 group_by other_id limit 10”(可怕的假装语法)会返回按 other_id 分组的 10 个实例,或 10 个组(这就是我想要的)每个都有一个实例。

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


【解决方案1】:

在单个 SQL 查询中,可以使用 PostgreSQL 特有的 SELECT DISTINCT ON... 轻松实现。

http://www.postgresql.org/docs/current/static/sql-select.html

SELECT DISTINCT ON (表达式 [, ...] ) 只保留第一行 给定表达式计算结果为等于的每组行。这 DISTINCT ON 表达式使用与 for 相同的规则进行解释 订购(见上文)。请注意,每组的“第一行”是 不可预测,除非使用 ORDER BY 来确保所需的行 首先出现

用你的例子:

 SELECT DISTINCT ON (other_id) * 
 FROM instances
 WHERE user_id = 3 
 ORDER BY other_id LIMIT 10

【讨论】:

  • 完美无瑕 :) 完美!不知道 DISTINCT ON 的存在,所以感谢你教我一些新东西!对于任何想知道的人,当我将其添加到我的 rails 应用程序时,它的外观如下:Instance.select("DISTINCT ON (other_id) *").where({:user_id =&gt; 3}).order("other_id").limit(10)
  • 这确实让我想到了另一个问题,这很好,总是在学习新东西。我现在很好奇我是否可以避免现在检查是否有可能避免循环遍历 ruby​​-land 中的那些来进行另一个过滤器。这似乎不太可能且难以解释,所以我将发布另一个问题 :) 感谢 TON 的帮助!
  • 如果有人觉得可以提供帮助,请在此处添加 :) stackoverflow.com/questions/21925712/…。 @Daniel Verite,我欠你一杯啤酒。
猜你喜欢
  • 2016-08-09
  • 1970-01-01
  • 2014-11-19
  • 2021-08-05
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多