查找不存在关联记录的父记录

时间:2017-07-22 06:04:29

标签: ruby-on-rails database postgresql

这是我所拥有的协会。

award_test.rb

has_many :instructor_student_awards , :dependent => :destroy
has_many :award_test_payment_notifications, dependent: :destroy

instructor_student.rb

has_many :instructor_student_awards, :dependent => :destroy
has_many :awards, through: :instructor_student_awards
has_many :award_test_payment_notifications, dependent: :destroy

instructor_student_award.rb

belongs_to :award
belongs_to :instructor_student
belongs_to :award_test

award_test_payment_notification.rb

belongs_to :award_test
belongs_to :instructor_student

schema.rb

"award_tests"
    t.date     "test_date"
    t.time     "test_time"
    t.integer  "award_id"
    t.decimal  "test_fee"


"award_test_payment_notifications"
    t.text     "response_params"
    t.string   "status"
    t.string   "transaction_id"
    t.string   "paid_by"
    t.float    "amount"
    t.string   "merchant_reference"
    t.integer  "award_test_id"
    t.integer  "instructor_student_id"

 "instructor_student_awards"
    t.integer  "instructor_student_id"
    t.integer  "award_test_id"
    t.boolean  "is_registered",         default: false

任何教师学生都可以报名参加奖励考试。一名教师学生可以在多个奖项考试中注册。   教师学生必须支付考试费用。教师学生可以通过2种方式进行奖励测试。

  1. 在线

  2. 现金

  3. 当讲师学生为该奖项考试付费时。比教师学生和award_test数据将插入award_test_payment_notifications。 award_test_notifications表包含与学生和奖励测试相关的所有领域。

    如果教师学生不支付该奖励测试的费用而不是未付费,那么奖励测试支付通知将仅在该奖励测试中为零。

    指导学生1注册3个奖项测试,如10,11,12。

    讲师学生1支付现金进行奖励测试10。

    讲师学生1在线支付奖励测试12。

    教师学生1没有为奖励测试11付款。

    所以教师学生有2个奖励考试付款通知   1)奖励测试10 2)奖励测试12

    当我在2017年1月1日至2017年7月31日期间搜索奖励测试时,此3个奖项属于此过滤器     教师1将返回3个类别。

    1. 现金支付

    2. 在线支付

    3. 未付

    4. 我有2个日期,我需要根据2个日期过滤数据。该日期将是测试日期。我必须区分所有现金支付,在线支付和未支付。

      以下是我为获得现金支付和在线支付所做的查询。

      current_admin_award_test = AwardTest.joins(instructor_student_awards: {:instructor_student => :award_test_payment_notifications}).where("test_date <= ? AND test_date >= ? AND instructor_student_awards.instructor_student_id  IN (?) ", @endMonth.end_of_month, @startMonth.beginning_of_month, @all_instructor_student_ids)
      
      @award_test_cash = current_admin_award_test.joins("INNER JOIN award_test_payment_notifications atn ON award_test_payment_notifications.award_test_id = award_tests.id").where("award_test_payment_notifications.paid_by = ? ","Cash").select("DISTINCT(award_tests.id), instructor_student_awards.instructor_student_id, award_test_payment_notifications.paid_by, award_tests.test_fee, award_tests.test_date")
      
      @award_test_paid_online = current_admin_award_test.joins("INNER JOIN award_test_payment_notifications atn ON award_test_payment_notifications.award_test_id = award_tests.id").where("award_test_payment_notifications.paid_by <> ? ","Cash").select("DISTINCT(award_tests.id), instructor_student_awards.instructor_student_id, award_test_payment_notifications.paid_by, award_tests.test_fee, award_tests.test_date")
      

      工作正常。但我被困在如何获得一名教练学生多次奖励测试的无薪奖励测试清单。

      更新1

        

      InstructorStudentAward的作用是什么?

           

      当讲师学生注册奖励考试时。登录的数据   讲师学生奖。

           

      如果为该AwardTest记录了任何付款,则假定该事件   全额付清。 OK?

           

      是。当讲师学生支付奖励考试时。奖励测试付款   通知将被记录,无论金额是多少。

           

      是否为每个人创建了一个InstructorStudentAward关联   注册AwardTest的InstructorStudent?

           

      是的,你是对的。

           

      所以你想要的是,任何InstructorStudentAward加入AwardTest JOIN   缺少关联的InstructorStudent对   AwardTestPaymentNotification

           

           

      我可以假设您正在使用PostgreSQL数据库

           

      是的,我正在使用PostgreSQL数据库。

1 个答案:

答案 0 :(得分:0)

我添加了这个github repo,其中包含我需要的部分问题(以及一些你没有提及的内容)来复制你的关联结构。

https://github.com/kingdonb/ashvin-stackoverflow-post

项目根目录中的

example.rb是一个Rails Runner脚本,我想这里会复制这些东西是如何创建和链接在一起的。

您的查询,重新格式化有点可读:

current_admin_award_test = AwardTest.joins(
  instructor_student_awards: {
    :instructor_student => :award_test_payment_notifications
  }).where("test_date <= ? AND test_date >= ?
    AND instructor_student_awards.instructor_student_id
    IN (?) ",
  @endMonth.end_of_month,
  @startMonth.beginning_of_month, @all_instructor_student_ids)

@award_test_cash = current_admin_award_test.joins(
  "INNER JOIN award_test_payment_notifications atn ON
  award_test_payment_notifications.award_test_id = 
    award_tests.id").
  where(
    "award_test_payment_notifications.paid_by = ? ", "Cash"
  ).select(
  "DISTINCT(award_tests.id),
   instructor_student_awards.instructor_student_id,
   award_test_payment_notifications.paid_by,
   award_tests.test_fee, award_tests.test_date")

@award_test_paid_online = current_admin_award_test.joins(
  "INNER JOIN award_test_payment_notifications atn ON
  award_test_payment_notifications.award_test_id =
    award_tests.id").
  where(
    "award_test_payment_notifications.paid_by <> ? ","Cash"
  ).select(
  "DISTINCT(award_tests.id),
   instructor_student_awards.instructor_student_id,
   award_test_payment_notifications.paid_by,
   award_tests.test_fee, award_tests.test_date")

我认为缺少的查询,如果您打算这样做,可以从current_admin_award_test派生,因为它默默地进行内部联接。当你说&#34;加入&#34;没有其他上下文,Rails推断您的意思是内部加入:https://apidock.com/rails/ActiveRecord/QueryMethods/joins#docs_body

看看结果:

current_admin_award_test = AwardTest.joins(
  instructor_student_awards: {
    :instructor_student => :award_test_payment_notifications
  })

你只回来付费的InstructorStudentAwards!

因此,删除不具有匹配的AwardTestPaymentNotifications的记录,因为内部联接需要双方匹配才能生成行结果。因此,如果您从该关联对象开始查询,它将永远不会返回任何未付的记录。

你想:

@award_test_unpaid = AwardTest.left_outer_joins(
  instructor_student_awards: {
    instructor_student: :award_test_payment_notifications
  }).where(award_test_payment_notifications: { id: nil } ).

[ and the rest of your criteria from current_admin_award_test ]

  where("test_date <= ? AND test_date >= ?
    AND instructor_student_awards.instructor_student_id
    IN (?) ",
  @endMonth.end_of_month,
  @startMonth.beginning_of_month, @all_instructor_student_ids)

如果您使用的是旧版本的Rails,则会变得更复杂,因为#left_outer_joins仅在Rails 5.0中添加。

如果您想改进这一点,可以将current_admin_award_test设置为不加入award_test_payment_notifications的参数化范围(您已经加入该表以制作每个派生的付款状态列表,我担心这会加入两次,这可能是你不得不求助于使用DISTINCT ......?还是有其他原因?)

也许他们为一个AwardTest有多个AwardTestPaymentNotifications,你并不想从中获得重复的AwardTest记录。好。您也可以使用此新范围作为@award_test_unpaid的基础。

scope :current_admin_award_test, ->(
  end_date, begin_date, instructor_student_list) {
    joins(instructor_student_awards: :instructor_student).
    where("test_date <= ? AND test_date >= ?",
      end_date.end_of_month, begin_date.beginning_of_month).
    where(instructor_student_awards:
      { instructor_student: instructor_student_list }
    )
  }

(GitHub项目的in context)我把它放在了AwardTest模型的提交中。

您的三个私有变量也可以是范围,具有相同的参数(将它们传递给此主范围,处理日期逻辑。)

(在给出疑问的好处之内,你可能已经在你的模型中有这些东西,但是根本没有将它们包含在问题中,因为你并不想在其中加入过多的代码。)

因此,如果教练学生没有支付他的一张账单,他的AwardTest将出现在此列表中。如果所有账单都已付清,那么InstructorStudent将不会出现在此列表中。我认为那是你想要达到的目标吗?

如果您想进一步推导出包含未付账单的InstructorStudent记录列表,那么您可以向每个记录发送一份措辞强烈的电子邮件,现在看起来就像这样:

@award_test_unpaid.
  map(&:instructor_student_awards).flatten.
  map(&:instructor_student).
  map(&:id).uniq

为了获得奖金,我只是花了一些时间在我站起来的回购中,充实了rails关联和范围,以便有一个current_unpaid范围,大致与你想要的一样。

scope :current_unpaid, ->(
  end_date, begin_date, instructor_student_list) {
  current_admin_award_test(end_date, begin_date, instructor_student_list).
    left_outer_joins(:award_test_payment_notifications).
      where(award_test_payment_notifications: { id: nil } )
  }

2017-08-04编辑:@ashvin透露他在Rails 4.1上,所以.left_outer_join没有工作,因为它没有被添加到Rails 5 ...这个原始的SQL将工作取而代之的是:

 scope :current_unpaid, ->(
   end_date, begin_date, instructor_student_list) {
   current_admin_award_test(end_date, begin_date, instructor_student_list).
     joins("LEFT JOIN award_test_payment_notifications
             ON award_tests.id =
                award_test_payment_notifications.award_test_id
            AND instructor_students.id =
                award_test_payment_notifications.instructor_student_id").
       where(award_test_payment_notifications: { id: nil } )
   }

然后你可以

AwardTest.current_unpaid(Date.today, Date.today, InstructorStudent.all.map(&:id))

并获取当月所有未付奖励测试的列表!

这取决于在has_many :award_test_payment_notifications模型上设置AwardTest。它还取决于我们在上面进一步定义的current_admin_award_test范围。进行此项工作的所有更改都在此提交中:more time on rails associations。希望这有帮助!