Sql RubyonRails:带Sort的左外连接

Sql RubyonRails:带Sort的左外连接,sql,ruby-on-rails,ruby,ruby-on-rails-3,join,Sql,Ruby On Rails,Ruby,Ruby On Rails 3,Join,我有一个用于发送电子邮件的RoR应用程序,我有联系人、收件人和用户模型,用户可以有多个联系人,联系人可以有多个收件人。数据如下所示: User ID Name 1 Ben 2 Emily 3 Brian Contact ID Name User_ID 1 Jack 1 2 Joe 2 3 Chloe 2 4 Jacob 1 5

我有一个用于发送电子邮件的RoR应用程序,我有联系人、收件人和用户模型,用户可以有多个联系人,联系人可以有多个收件人。数据如下所示:

 User
 ID     Name
 1      Ben
 2      Emily
 3      Brian

 Contact
 ID       Name     User_ID
 1        Jack     1
 2        Joe      2
 3        Chloe    2
 4        Jacob    1
 5        Trevor   3

 Recipient
 ID     Contact_ID     Email_ID (not relevant for this question)
 1      1              2
 2      1              1
 3      4              5
 4      1              6
 5      2              8
Contact.includes(:recipients).references(:recipients).group("contacts.id, recipients.id").order("COUNT(recipients.id) ASC")
我想做的是在联系人的索引页面上,显示属于用户的所有联系人,允许用户选择订购方式,例如姓名和收到的电子邮件数量

我的问题是,我可以显示属于某个用户的所有联系人,这没有问题,但我很难允许用户根据收到的电子邮件数量对联系人进行排序。他们收到的电子邮件数量可以通过计算具有相同联系人id的收件人数量来计算。我出现此问题的原因是,我想显示属于某个用户的所有联系人,而不管他们是否收到电子邮件(一个联系人可能收到0封电子邮件)。我尝试过的代码是:

@contacts = Contact.where(user_id: session[:user_id]).all.order(params.fetch(:sort, 'id asc'))
但这不允许用户根据联系人收到的电子邮件数量进行排序

我也试过:

  @contacts = Contact.where(user_id: session[:user_id]).joins(:recipients).group('contacts.id').all.order(params.fetch(:sort, 'id asc'))
@contacts = Contact.where(user_id: session[:user_id]).joins("LEFT OUTER JOIN contacts ON contacts.id = recipients.contact_id").all.order('max(recipients.contact_id) DESC')
但这只显示收到电子邮件的联系人

我也试过:

  @contacts = Contact.where(user_id: session[:user_id]).joins(:recipients).group('contacts.id').all.order(params.fetch(:sort, 'id asc'))
@contacts = Contact.where(user_id: session[:user_id]).joins("LEFT OUTER JOIN contacts ON contacts.id = recipients.contact_id").all.order('max(recipients.contact_id) DESC')
这将显示所有收到和未收到电子邮件的联系人,并允许排序,但会显示重复数据。即,使用上述数据,如果Ben查看他的联系人(用户id 1),他可以看到Jack和Jacob,但由于Jack已收到3封电子邮件,他会看到以下内容:

First Name:
Jack
Jacob
Jack
Jack
Jack
有办法解决这个问题吗?请注意,我目前正在使用
index.html.erb
上的以下代码,以允许用户通过以下方式选择要订购的记录:

<form>
    Order By:
    <select name="sort">
        <option value="firstname ASC">First Name (A - Z)</option>
        <option value="firstname DESC">First Name (Z - A)</option>
        <option value="surname ASC">Surname (A - Z)</option>
        <option value="surname DESC">Surname (Z - A)</option>
        <option value="email ASC">Email (A - Z)</option>
        <option value="email DESC">Email (Z - A)</option>
        <option value="max(recipients.contact_id) ASC">Emails Recieved (Low - High)</option>
        <option value="max(recipients.contact_id) DESC">Emails Recieved (High - Low)</option>

        <option value="updated_at ASC">Date Updated (Oldest First)</option>
        <option value="updated_at DESC">Date Updated (Newest First)</option>
    </select>
    <button>
        Go
    </button>
</form>

订购人:
名字(A-Z)
名字(Z-A)
姓氏(A-Z)
姓氏(Z-A)
电子邮件(A-Z)
电子邮件(Z-A)
收到的电子邮件(低-高)
收到的电子邮件(高-低)
更新日期(最早的第一个)
更新日期(最新第一次)
去
试试这个

@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
                   .where(user_id: session[:user_id])
                   .joins(:recipients)
                   .group('contacts.id')
                   .order('emails_received ASC')
如果你想显示那些没有收到电子邮件的人,你需要加入

@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
                   .where(user_id: session[:user_id])
                   .joins('LEFT OUTER JOIN recipients ON recipients.contact_id = contacts.id)
                   .group('contacts.id')
                   .order('emails_received ASC')
试试这个

@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
                   .where(user_id: session[:user_id])
                   .joins(:recipients)
                   .group('contacts.id')
                   .order('emails_received ASC')
如果你想显示那些没有收到电子邮件的人,你需要加入

@contacts = Contact.select('contacts.*, count(recipients.id) as emails_received')
                   .where(user_id: session[:user_id])
                   .joins('LEFT OUTER JOIN recipients ON recipients.contact_id = contacts.id)
                   .group('contacts.id')
                   .order('emails_received ASC')

要进行左外连接,请尝试以下操作:

Contact.includes(:recipients).references(:recipients)
注意:这还将预加载收件人并向查询中添加大量SQL

如果您还想进行排序,那么您应该能够这样做:

 User
 ID     Name
 1      Ben
 2      Emily
 3      Brian

 Contact
 ID       Name     User_ID
 1        Jack     1
 2        Joe      2
 3        Chloe    2
 4        Jacob    1
 5        Trevor   3

 Recipient
 ID     Contact_ID     Email_ID (not relevant for this question)
 1      1              2
 2      1              1
 3      4              5
 4      1              6
 5      2              8
Contact.includes(:recipients).references(:recipients).group("contacts.id, recipients.id").order("COUNT(recipients.id) ASC")

要进行左外连接,请尝试以下操作:

Contact.includes(:recipients).references(:recipients)
注意:这还将预加载收件人并向查询中添加大量SQL

如果您还想进行排序,那么您应该能够这样做:

 User
 ID     Name
 1      Ben
 2      Emily
 3      Brian

 Contact
 ID       Name     User_ID
 1        Jack     1
 2        Joe      2
 3        Chloe    2
 4        Jacob    1
 5        Trevor   3

 Recipient
 ID     Contact_ID     Email_ID (not relevant for this question)
 1      1              2
 2      1              1
 3      4              5
 4      1              6
 5      2              8
Contact.includes(:recipients).references(:recipients).group("contacts.id, recipients.id").order("COUNT(recipients.id) ASC")

您需要合计(读取计数)收到的电子邮件数量,例如选择('count(recipients.id)as emails_received')。组('contacts.id')如何允许用户订购?您的意思是
订购('count(recipients.id)ASC')
?那么就像that@engineersmnky我相信您需要在
选择中进行
计数
。@engineersmnky那么整行是什么样子的呢
@contacts=Contact.where(user\u id:session[:user\u id])。选择('count(recipients.id)as email\u received')。组('contacts.id')。所有.order('count(recipients.id)ASC')
?您需要聚合(读取计数)收到的电子邮件数量,例如选择('count(recipients.id)as email\u received')。组('contacts.id'))这将如何允许用户订购它们?您的意思是
订购('count(recipients.id)ASC')
?那么就像that@engineersmnky我相信您需要在
选择中进行
计数
。@engineersmnky那么整行是什么样子的呢
@contacts=Contact.where(user_id:session[:user_id])。选择('count(recipients.id)as email_received')。组('contacts.id')。全部。订单('count(recipients.id)ASC')
?谢谢,但这给了我一个错误:
SQLite3::SQLException:没有这样的列:reci‌​pients.id:选择contacts.*,将(recipients.id)计算为从“联系人”内部接收的电子邮件,并在“收件人”上加入“收件人”。“联系人id”=“联系人”。“id”中的“联系人”。“用户id”=?按联系人分组。id按计数排序(reci‌​pients.id)ASC
我删除了
.order('count(reci‌​id)ASC')
查看是否会显示所有联系人。不幸的是,它没有显示未收到电子邮件的联系人-因此那些未出现在收件人表中的联系人。@BenSmith oops。。。我的错。忘了换了。应该是
.order('emails\u received ASC')
谢谢,但这给了我一个错误:
SQLite3::SQLException:没有这样的列:reci‌​pients.id:选择contacts.*,将(recipients.id)计算为从“联系人”内部接收的电子邮件,并在“收件人”上加入“收件人”。“联系人id”=“联系人”。“id”中的“联系人”。“用户id”=?按联系人分组。id按计数排序(reci‌​pients.id)ASC
我删除了
.order('count(reci‌​id)ASC')
查看是否会显示所有联系人。不幸的是,它没有显示未收到电子邮件的联系人-因此那些未出现在收件人表中的联系人。@BenSmith oops。。。我的错。忘了换了。应该是
.order('emails\u received ASC')
虽然我无法让订单正常工作,但这似乎有效?@BenSmith我还添加了一个如何进行排序的示例。我已经在Postgres上测试了这样一个有效的查询,非常好!非常感谢。虽然我无法进行排序,但这似乎可行?@BenSmith我还添加了一个如何进行排序的示例。我已经在Postgres上测试了这样一个有效的查询,非常好!非常感谢。