我对COUNT(' e.id')或COUNT(e.id)的查询有不同的结果

时间:2018-04-29 12:58:08

标签: postgresql ruby-on-rails-4 activerecord count left-join

我有以下代码:

"@angular/animations": "4.4.6",
"@angular/cdk": "2.0.0-beta.12",
"@angular/common": "4.4.6",
"@angular/compiler": "4.4.6",
"@angular/core": "4.4.6",
"@angular/forms": "4.4.6",
"@angular/material": "2.0.0-beta.12",
"@angular/http": "4.4.6",
"@angular/platform-browser": "4.4.6",
"@angular/platform-browser-dynamic": "4.4.6",
"@angular/router": "4.4.6",
"@liwebcorp/tron": "1.0.0",
"bootstrap": "3.3.7",
"browserslist": "^2.4.0",
"classlist.js": "^1.1.20150312",
"core-js": "2.5.1",
"highcharts": "^6.0.3",
"jquery": "^3.2.1",
"ng2-auto-complete": "0.12.0",
"ng2-bootstrap-modal": "^1.0.1",
"ng2-daterangepicker": "2.0.7",
"ng2-drag-drop": "2.9.2",
"ng2-toastr": "^4.1.2",
"ng2-tooltip-directive": "^1.2.3",
"ngx-file-drop": "^2.0.4",
"ngx-malihu-scrollbar": "^1.3.1",
"popper.js": "1.12.9",
"rxjs": "5.5.2",
"web-animations-js": "^2.3.1",
"zone.js": "0.8.17"

当我使用

def self.department_members(department)
  where(organization_id: department.organization_id)
    .joins("LEFT JOIN core_employments As e ON
      e.organization_id = #{department.organization_id} AND
      core_members.user_id = e.user_id")
    .group('core_members.id')
end

def self.can_automerged(department)
  department_members(department).having("COUNT('e.id') = 1")
  # department_members(department).having("COUNT(e.id) = 1")
end

def self.can_not_automerged(department)
  department_members(department).having("Count('e.id') > 1")
end

我的测试完成没有错误。当我使用

department_members(department).having("COUNT('e.id') = 1")

我的测试失败了。我不明白为什么。你能解释一下原因吗? 我使用Rails-4和PostgreSQL。

架构:

department_members(department).having("COUNT(e.id) = 1")

试验:

  create_table "core_members", force: :cascade do |t|
    t.integer  "user_id",                                    null: false
    t.integer  "project_id",                                 null: false
    t.boolean  "owner",                      default: false
    t.string   "login"
    t.string   "project_access_state"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "organization_id"
    t.integer  "organization_department_id"
  end

  create_table "core_employments", force: :cascade do |t|
    t.integer  "user_id"
    t.integer  "organization_id"
    t.boolean  "primary"
    t.string   "state"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.integer  "organization_department_id"
  end

1 个答案:

答案 0 :(得分:3)

  

我对COUNT(' e.id')或COUNT(e.id)的查询有不同的结果

COUNT('e.id')是一个字符串常量,因此COUNT(*)只是一种尴尬,误导性的说法COUNT(e.id)

另一方面,

e.id IS NOT NULL计算结果中count()的所有行 - 因为count(*)不计算NULL值。

The manual about count():

  

count(expression) ...输入行数

     

count(*) ...输入行数   表达式的值不为空

如您所见,内部甚至还有两个独立的功能。和 应该注意的是e.id稍快一些。所以除非你需要第二种变体,否则请使用它。相关:

你可以反驳:
"但PRIMARY KEYcore_employments的{​​{1}},因此定义为NOT NULL!"

但这会忽略您的查询中的条件LEFT JOIN ,但仍会在NULL列中引入NOT NULL值,但不符合连接条件。相关:

尽管如此,LEFT [OUTER] JOIN也具有误导性。后来的条件

having("COUNT(e.id) = 1")

迫使它像普通[INNER] JOIN一样行事。修好后,您可以简化为:

having("COUNT(*) = 1")

如果您关心的是 至少 core_employments中存在一个相关行,则转换为having("COUNT(*) >= 1"),上级(更清楚,更简单的情况下,技术将是EXISTS semi-join

WHERE EXISTS (SELECT FROM core_employments WHERE <conditions>)