【问题标题】:Selecting columns with DISTINCT in PostgreSQL在 PostgreSQL 中选择具有 DISTINCT 的列
【发布时间】:2011-02-15 20:46:27
【问题描述】:

我正在从数据库中查询公交车站,我希望它只返回每个公交线路/方向的 1 个站点。这个查询就是这样做的:

Stop.select("DISTINCT line_id, direction")

除了它不会为我提供除这 2 之外的任何其他属性。我尝试了其他几个查询让它返回 id 除了 line_iddirection 字段(理想情况下它会返回所有列),没有运气:

Stop.select("DISTINCT line_id, direction, id")

Stop.select("DISTINCT(line_id || '-' || direction), id")

在这两种情况下,查询都会丢失其 distinct 子句并返回所有行。

一些很棒的家伙帮助了我,并建议使用子查询让它返回所有的 id:

Stop.find_by_sql("SELECT DISTINCT a1.line_id, a1.direction, (SELECT a2.id from stops a2 where a2.line_id = a1.line_id AND a2.direction = a1.direction ORDER BY a2.id ASC LIMIT 1) as id FROM stops a1

然后我可以提取所有 id 并执行第二次查询以获取每个站点的完整属性。

有没有办法将所有内容都包含在 1 个查询中并返回所有属性?

【问题讨论】:

  • 我不确定你的要求是否有意义。要么你想要停止,要么你不想要。如果您想要停靠点,将会有更多行。如果您想在列中停止 id,请将 array_agg 包裹在子查询周围并删除限制。似乎您将在此之后进行一些查询,或者为什么只返回 stop_ids。我认为最好在问题中说明想要什么。人们可能更容易回答
  • 我想要停靠点,只是我只想要每行/方向一个。因此,如果一条公交线路有 2 个方向,我希望查询返回每个方向的 1 个站点。 @pothibo 的回答是正确的,无论如何,谢谢。

标签: ruby-on-rails postgresql activerecord


【解决方案1】:
Stop.select("DISTINCT ON (line_id, direction) *")

【讨论】:

  • 不错。以前没见过。这个问题是 postgres 特有的,所以这个答案很好,但值得注意的是,它看起来像是一个 postgres 特有的答案postgresql.org/docs/8.1/static/queries-select-lists.html
  • 实际上 'DISTINCT (line_id, direction), *' 对于我来说也适用于 postgres
【解决方案2】:

没那么快 - 另一个答案选择 stop_id 任意

这就是为什么你的问题没有意义。我们可以拉 stop_ids 并有不同的 line_id 和方向。但我们不知道为什么我们有我们所做的 stop_id。

    create temp table test( line_id integer, direction char(1), stop_id      integer);
    insert into test values
            (1, 'N', 1),
            (1, 'N', 2),
            (1, 'S', 1),
            (1, 'S', 2),
            (2, 'N', 1),
            (2, 'N', 2),
            (2, 'S', 1),
            (2, 'S', 2)
    ;
    select distinct on (line_id, direction) * from test;
    -- do this again but will reverse the order of stop_ids
    -- could it possible change our Robust Query?!!!
    drop table test;
    create temp table test(line_id integer,direction char(1),stop_id integer);
    insert into test values
            (1, 'N', 2),
            (1, 'N', 1),
            (1, 'S', 2),
            (1, 'S', 1),
            (2, 'N', 2),
            (2, 'N', 1),
            (2, 'S', 2),
            (2, 'S', 1)
    ;
    select distinct on (line_id, direction) * from test;

首先选择:

line_id | direction | stop_id 
---------+-----------+---------
       1 | N         |       1
       1 | S         |       1
       2 | N         |       1
       2 | S         |       1

第二次选择:

line_id | direction | stop_id 
---------+-----------+---------
       1 | N         |       2
       1 | S         |       2
       2 | N         |       2
       2 | S         |       2

所以我们没有分组 stop_id 就逃脱了,但我们不能保证为什么我们得到了那个 我们做到了。我们只知道这是有效的 stop_id。任何更新、插入和其他 没有 RDMS 可以保证的东西可以围绕行的物理顺序发生变化。

这就是我在顶部评论中的意思。没有已知的理由将一个 stop_id 拉到另一个之上,但不知何故,您迫切需要这个 stop_id(或其他任何东西)。

【讨论】:

  • 明白了。就我而言,我将按与用户的距离对结果进行排序。添加 ORDER BY 子句是否会确保选择第一个 stop_id?
  • 您的警告有效。但问题不在于结果的有效性。这是关于查询本身是错误的。我猜这个查询是一个简单的测试,而不是实际的查询。
猜你喜欢
  • 2015-06-07
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 2021-02-06
相关资源
最近更新 更多