排序列必须出现在GROUP BY子句中

时间:2018-11-21 17:54:20

标签: elixir phoenix-framework ecto

我在phoenix应用程序中使用了数据库。我有一个buses表,每个表都与一个或多个stopsroutes相关联。我正在尝试列出所有站点的可搜索列表,但是我不想重写我的搜索和过滤功能(请参见list_filtered_buses)。

因此,在sort_bus_list中,我试图返回所有停靠站的排序列表。 当前实施方式的问题是,由于在返回每个总线的所有停靠点后,在模板中呈现列表时会返回重复项。我尝试了两种不同的方法,一种返回重复项,还有一个可以防止由于错误而进行排序。

这是buses.ex中sort_bus_list中的相关代码:

  # V1 - sortable, but returns duplicates
  list
    |> order_by([b, s, r], {^attrs.sort_dir, field(s, ^attrs.sort_attr)})
    |> group_by([b, s, r], [s.id, b.id])

  # V2 - doesn't return duplicates, but isn't returns error:
  # ERROR 42803 (grouping_error): column "b1.stop_id" must appear in the GROUP BY clause or be used in an aggregate function
    list
    |> order_by([b, s, r], {^attrs.sort_dir, field(s, ^attrs.sort_attr)})
    |> group_by([b, s, r], b.id)

这是我模板的伪代码:

for bus in Buses
    for stop in bus
        display stop
    end
end 

更多buses.ex代码用于上下文:

 def list_filtered_buses(params) do
  search_term = params["filter"]["query"]

  from(t in Bus, join: a in assoc(t, :stops), join: c in assoc(t, :routes))
  |> search(search_term)
  |> list_buses_by_active(params)
  |> list_buses_by_type(params)
  |> sort_buses_list(params)
  |> preload([:stops, :routes])
 end


def sort_bus_list(list, params) do
  attrs = process_sorting_metrics(params)

  case params["filter"]["sort_attr"] do
    a when a == "stop_name" or a == "stop_id" ->

  #V2 - sortable, but returns duplcate
  list
    |> order_by([b, s, r], {^attrs.sort_dir, field(s, ^attrs.sort_attr)})
    |> group_by([b, s, r], [s.id, b.id])

  "route_name" ->
    list
    |> order_by([b, s, r], {^attrs.sort_dir, field(r, ^attrs.sort_attr)})
    |> group_by([b, s, r], [b.id, r.id])

  _ ->
    list
    |> order_by([b, s, r], {^attrs.sort_dir, field(b, ^attrs.sort_attr)})
    |> group_by([b, s, r], b.id)
  end
end

1 个答案:

答案 0 :(得分:1)

看起来,您正在尝试仅渲染Stop。在list_filtered_buses函数中,您正在Bus表上运行查询。然后,您进一步尝试对数据进行排序和分组。 #V1函数正在Bus.idStop.id上进行分组,因此如果不同的Stop具有相同的Bus,则会得到重复的Stop。但是,#V2函数返回错误,因为您正在select上进行Bus查询,而仅在group。id上进行Bus,并尝试从Stop

如@AlekseiMatiushkin所建议的,为了仅渲染不同的Stop,需要执行from(s in Stop)