1

在我的网站中,我的用户有一个属性localidade。这指定了他们居住的地方。

我正在尝试进行查询,并按以下方式对结果进行分组:

localidade   | Number of Users
-------------+--------------
New York     | 6
Not New York | 8

我想要来自纽约的用户数量以及来自纽约以外任何地方的用户数量。

我试过这个:

User.group("lower(localidade) = 'new york'").count

但由于我没有来自纽约的任何用户,而且只有 1 个不是来自纽约的用户,所以它返回:

{false => 1}

我可以给群组起别名吗?有没有办法以这种方式对结果进行分组?

我会将结果用于 Graphkick 的饼图。

4

2 回答 2

2

你可以写你的查询:

User.group("lower(localidade)")
    .select("CASE WHEN lower(localidade) = 'new york' THEN COUNT(id) END AS NewYork, 
             CASE WHEN lower(localidade) != 'new york' THEN COUNT(id) END AS Non-NewYork")

9.4 开始,您可以使用FILTERwith聚合表达式

User.group("lower(localidade)")
    .select("COUNT(id) FILTER (WHERE lower(localidade) != 'new york') AS NonNewyork, 
             COUNT(id) FILTER (WHERE lower(localidade) = 'new york') AS Newyork")

我创建了一个表来解释和测试上面的 sql,它们按预期工作:

[shreyas@rails_app_test (master)]$ rails db
psql (9.4.1)
Type "help" for help.

app_development=# select id, location, name from people;
 id | location | name
----+----------+------
  2 | X        | foo
  3 | X        | foo
  4 | Y        | foo
(3 rows)

app_development=# SELECT COUNT(id) FILTER(WHERE lower(location) != 'x') AS Non_X_loc, COUNT(id) FILTER (WHERE lower(location) = 'x') AS X_loc FROM "people";
 non_x_loc | x_loc
-----------+-------
         1 |     2
(1 row)

现在让我跳到 rails 控制台,并测试等效的 Rails 代码:

[2] pry(main)> p = Person.select("COUNT(id) FILTER(WHERE lower(location) != 'x') AS Non_X_loc, COUNT(id) FILTER (WHERE lower(location) = 'x') AS X_loc ")
  Person Load (0.5ms)  SELECT COUNT(id) FILTER(WHERE lower(location) != 'x') AS Non_X_loc, COUNT(id) FILTER (WHERE lower(location) = 'x') AS X_loc  FROM "people"
=> [#<Person:0x007fd85ed71980 id: nil>]
[3] pry(main)> p.first.attributes
=> {"id"=>nil, "non_x_loc"=>1, "x_loc"=>2}
[6] pry(main)> Person.group("lower(location)").select("CASE WHEN lower(location) = 'x' THEN COUNT(id) END AS X_loc, CASE WHEN lower(location) != 'x' THEN COUNT(id) END AS Non_X_loc")
  Person Load (0.6ms)  SELECT CASE WHEN lower(location) = 'x' THEN COUNT(id) END AS X_loc, CASE WHEN lower(location) != 'x' THEN COUNT(id) END AS Non_X_loc FROM "people" GROUP BY lower(location)
=> [#<Person:0x007fd8608281e8 id: nil>, #<Person:0x007fd860828008 id: nil>]
[7] pry(main)> p = _
=> [#<Person:0x007fd8608281e8 id: nil>, #<Person:0x007fd860828008 id: nil>]
[8] pry(main)> p.map { |rec| rec.attributes }
=> [{"id"=>nil, "x_loc"=>nil, "non_x_loc"=>1}, {"id"=>nil, "x_loc"=>2, "non_x_loc"=>nil}]
[9] pry(main)> p.map { |rec| rec.attributes.except('id') }
=> [{"x_loc"=>nil, "non_x_loc"=>1}, {"x_loc"=>2, "non_x_loc"=>nil}]

更新

您只能nil从数据库级别删除那些:

导轨代码:

[shreyas@rails_app_test (master)]$ rails c
Loading development environment (Rails 4.2.0)
[1] pry(main)> Person.group("lower(location)").select("CASE WHEN lower(location) = 'x' THEN COUNT(id) ELSE 0 END AS X_loc, CASE WHEN lower(location) != 'x' THEN COUNT(id) ELSE 0 END AS Non_X_loc")
  Person Load (0.9ms)  SELECT CASE WHEN lower(location) = 'x' THEN COUNT(id) ELSE 0 END AS X_loc, CASE WHEN lower(location) != 'x' THEN COUNT(id) ELSE 0 END AS Non_X_loc FROM "people" GROUP BY lower(location)
=> [#<Person:0x007fd858c100b0 id: nil>, #<Person:0x007fd860853e88 id: nil>]
[2] pry(main)> p = _
=> [#<Person:0x007fd858c100b0 id: nil>, #<Person:0x007fd860853e88 id: nil>]
[3] pry(main)> p.map { |rec| rec.attributes }
=> [{"id"=>nil, "x_loc"=>0, "non_x_loc"=>1}, {"id"=>nil, "x_loc"=>2, "non_x_loc"=>0}]
[4] pry(main)> p.map { |rec| rec.attributes.except('id') }
=> [{"x_loc"=>0, "non_x_loc"=>1}, {"x_loc"=>2, "non_x_loc"=>0}]
[5] pry(main)> p = Person.select("count(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, count(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc").group("lower(location)")
  Person Load (0.9ms)  SELECT count(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, count(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc FROM "people" GROUP BY lower(location)
=> [#<Person:0x007fd85b150f78 id: nil>, #<Person:0x007fd85b150230 id: nil>]
[6] pry(main)> p.map { |rec| rec.attributes.except('id') }
=> [{"x_loc"=>0, "non_x_loc"=>1}, {"x_loc"=>2, "non_x_loc"=>0}]

SQL

app_development=# select CASE WHEN lower(location) = 'x' THEN COUNT(id) ELSE 0 END AS X_loc, CASE WHEN lower(location) != 'x' THEN COUNT(id) ELSE 0 END AS Non_X_loc from people group by lower(location);
 x_loc | non_x_loc
-------+-----------
     0 |         1
     2 |         0
(2 rows)
app_development=# select count(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, count(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc from people group by lower(location);
 x_loc | non_x_loc
-------+-----------
     0 |         1
     2 |         0
(2 rows)

更新-II

获得与FILTER相同的输出的经典方法:

app_development=# select count(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, sum(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc from people;
 x_loc | non_x_loc
-------+-----------
     2 |         1
(1 row)

app_development=# select sum(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, sum(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc from people;
 x_loc | non_x_loc
-------+-----------
     2 |         1
(1 row)

app_development=# select id, location, name from people;
 id | location | name
----+----------+------
  2 | X        | foo
  3 | X        | foo
  4 | Y        | foo
(3 rows)

app_development=#

并以 Rails 方式:-

Loading development environment (Rails 4.2.0)
[1] pry(main)> p = Person.select("sum(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, sum(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc")
  Person Load (0.6ms)  SELECT sum(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, sum(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc FROM "people"
=> [#<Person:0x007fd85b6e6a78 id: nil>]
[2] pry(main)> p.first.attributes.except("id")
=> {"x_loc"=>2, "non_x_loc"=>1}
[3] pry(main)> p = Person.select("count(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, count(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc")
  Person Load (0.5ms)  SELECT count(CASE WHEN lower(location) = 'x' THEN 1 END) AS X_loc, count(CASE WHEN lower(location) != 'x' THEN 1 END) AS Non_X_loc FROM "people"
=> [#<Person:0x007fd85b77f098 id: nil>]
[4] pry(main)> p.first.attributes.except("id")
=> {"x_loc"=>2, "non_x_loc"=>1}
[5] pry(main)>
于 2015-02-23T17:58:19.973 回答
0

老实说,您所拥有的一切都很好,您只需要了解,如果散列中没有值true(或false就此而言),则该值必须默认为零,您可以使用.to_i什么将是一个nil值来做到这一点。所以,例如:

ny_count = User.group("lower(localidade) = 'new york'").count

"New York: #{ny_count[true].to_i}
Not New York: #{ny_count[false].to_i}
"
于 2015-02-23T18:05:50.907 回答