0

ユーザーがGPAやスポーツ統計などの基準に基づいてアスリートを検索できる検索ページがあります。検索フィルターを1つだけ使用すると、PostgreSQLは正解を返します。複数の検索フィルターが使用されている場合、両方の検索フィルターで同じ統計が使用されている場合にのみ機能します。たとえば、「GPA>3」および「GPA== 4」を検索すると、対応するアスリートが返されます。「GPA>3」と「ACT>20」(どちらも同じアスリートに当てはまります)を実行すると、何も返されません(空の配列)。

このページ全体で参照できるように、@ conditionは次のようになります(ループを繰り返すことができるように、ハッシュではなくコード内で配列に変換されますが、要点はわかります)。

{
"0"=>{"category"=>"1", "stat_type_id"=>"22", "predicate"=>"Greater Than", 
"q"=>"2", "type"=>"stat"}, 

"1"=>{"category"=>"1", "stat_type_id"=>"2", 
"predicate"=>"Greater Than", "q"=>"10", "type"=>"stat"}
}

以下はコードです(Squeel構文):

def query
  relation = Athlete.listed.for_sport( self.sport )

  return relation if @conditions.blank?

  @conditions = @conditions.map { |k, v| v } if @conditions.is_a?(Hash)

  debugger

  @conditions.each do |condition|
    case condition[:type]
    when "stat"
      if !condition[:q].eql?("")
        relation = case condition[:predicate]
        when /less than/i
          relation.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.lt (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
        when /greater than/i
          relation.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.gt (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
        when /equal to/i
          relation.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.eq (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
        when /not equal to/i
          relation.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.not_eq (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
        end
      end
    when "academic"
      relation
    when "social"
      relation
    end
  end

  relation
end

以下に、ruby-debugから取得した2つのPostgreSQL呼び出しを含めました(PostgreSQLのRubyラッパーであるSqueelを使用しています)。両方の呼び出しを下にスクロールすると、最初の呼び出しと2番目の呼び出しが同じであることがわかりますが、2番目の呼び出しには余分なANDがあります(最初の呼び出しと同じ形式に従い、正常に機能するはずです)。

呼び出し1(1つのパラメーター):

SELECT "users"."id"                                  AS t0_r0,
       "users"."name"                                AS t0_r1,
       "users"."first_name"                          AS t0_r2,
       "users"."last_name"                           AS t0_r3,
       "users"."facebook_id"                         AS t0_r4,
       "users"."access_token"                        AS t0_r5,
       "users"."birthday"                            AS t0_r6,
       "users"."gender"                              AS t0_r7,
       "users"."device_token"                        AS t0_r8,
       "users"."current_city"                        AS t0_r9,
       "users"."hometown"                            AS t0_r10,
       "users"."relationship_status"                 AS t0_r11,
       "users"."avatar_file_name"                    AS t0_r12,
       "users"."avatar_content_type"                 AS t0_r13,
       "users"."avatar_file_size"                    AS t0_r14,
       "users"."avatar_updated_at"                   AS t0_r15,
       "users"."email"                               AS t0_r16,
       "users"."encrypted_password"                  AS t0_r17,
       "users"."reset_password_token"                AS t0_r18,
       "users"."reset_password_sent_at"              AS t0_r19,
       "users"."remember_created_at"                 AS t0_r20,
       "users"."sign_in_count"                       AS t0_r21,
       "users"."current_sign_in_at"                  AS t0_r22,
       "users"."last_sign_in_at"                     AS t0_r23,
       "users"."current_sign_in_ip"                  AS t0_r24,
       "users"."last_sign_in_ip"                     AS t0_r25,
       "users"."authentication_token"                AS t0_r26,
       "users"."created_at"                          AS t0_r27,
       "users"."updated_at"                          AS t0_r28,
       "users"."time_zone"                           AS t0_r29,
       "users"."username"                            AS t0_r30,
       "users"."middle_name"                         AS t0_r31,
       "users"."primary_sport_id"                    AS t0_r32,
       "users"."state"                               AS t0_r33,
       "users"."high_school"                         AS t0_r34,
       "users"."phone"                               AS t0_r35,
       "users"."user_type_id"                        AS t0_r36,
       "users"."agreed_to_terms_and_conditions"      AS t0_r37,
       "users"."agreed_to_information_integrity"     AS t0_r38,
       "users"."agreed_to_content_responsibility"    AS t0_r39,
       "users"."account_type_id"                     AS t0_r40,
       "users"."social_score"                        AS t0_r41,
       "users"."recruit_year"                        AS t0_r42,
       "users"."college_major"                       AS t0_r43,
       "users"."secondary_sport_id"                  AS t0_r44,
       "users"."handedness"                          AS t0_r45,
       "users"."checkdin_id"                         AS t0_r46,
       "users"."allow_twitter_sync"                  AS t0_r47,
       "users"."allow_facebook_sync"                 AS t0_r48,
       "users"."head_coach"                          AS t0_r49,
       "users"."head_coach_email"                    AS t0_r50,
       "users"."has_recruited_others"                AS t0_r51,
       "users"."customer_id"                         AS t0_r52,
       "users"."last_4_digits"                       AS t0_r53,
       "users"."removed_from_listing"                AS t0_r54,
       "users"."slug"                                AS t0_r55,
       "users"."college_minor"                       AS t0_r56,
       "users"."type"                                AS t0_r57,
       "users"."billing_expiration_month"            AS t0_r58,
       "users"."billing_expiration_year"             AS t0_r59,
       "users"."billing_name"                        AS t0_r60,
       "users"."billing_address"                     AS t0_r61,
       "users"."billing_city"                        AS t0_r62,
       "users"."billing_state"                       AS t0_r63,
       "users"."billing_zip"                         AS t0_r64,
       "users"."college_id"                          AS t0_r65,
       "users"."agreed_to_age_requirements"          AS t0_r66,
       "users"."primary_sport_primary_position_id"   AS t0_r67,
       "users"."secondary_sport_primary_position_id" AS t0_r68,
       "users"."recruit_status_id"                   AS t0_r69,
       "users"."active_flag"                         AS t0_r70,
       "users"."public"                              AS t0_r71,
       "invitations"."id"                            AS t1_r0,
       "invitations"."sender_id"                     AS t1_r1,
       "invitations"."role_id"                       AS t1_r2,
       "invitations"."to"                            AS t1_r3,
       "invitations"."accepted_at"                   AS t1_r4,
       "invitations"."token"                         AS t1_r5,
       "invitations"."created_at"                    AS t1_r6,
       "invitations"."updated_at"                    AS t1_r7,
       "invitations"."current_state"                 AS t1_r8,
       "invitations"."requester_id"                  AS t1_r9,
       "invitations"."user_type"                     AS t1_r10,
       "invitations"."type"                          AS t1_r11
FROM   "users"
       INNER JOIN "stats"
               ON "stats"."athlete_id" = "users"."id"
       LEFT OUTER JOIN "invitations"
                    ON "invitations"."requester_id" = "users"."id"
WHERE  "users"."removed_from_listing" = 'f'
       AND "users"."type" IN ( 'Athlete' )
       AND (( "invitations"."current_state" IN ( 'accepted' )
               OR "invitations"."current_state" IS NULL ))
       AND ( users.primary_sport_id = 13
              OR users.secondary_sport_id = 13 )
       AND (( "stats"."stat_type_id" = 22
              AND "stats"."value" > '2.0' )) 

結果はアスリートです。

呼び出し2(2つのパラメーター):

ただし、2番目の呼び出しは[]を返しますが、同じアスリートである必要があります...

SELECT "users"."id"                                  AS t0_r0,
       "users"."name"                                AS t0_r1,
       "users"."first_name"                          AS t0_r2,
       "users"."last_name"                           AS t0_r3,
       "users"."facebook_id"                         AS t0_r4,
       "users"."access_token"                        AS t0_r5,
       "users"."birthday"                            AS t0_r6,
       "users"."gender"                              AS t0_r7,
       "users"."device_token"                        AS t0_r8,
       "users"."current_city"                        AS t0_r9,
       "users"."hometown"                            AS t0_r10,
       "users"."relationship_status"                 AS t0_r11,
       "users"."avatar_file_name"                    AS t0_r12,
       "users"."avatar_content_type"                 AS t0_r13,
       "users"."avatar_file_size"                    AS t0_r14,
       "users"."avatar_updated_at"                   AS t0_r15,
       "users"."email"                               AS t0_r16,
       "users"."encrypted_password"                  AS t0_r17,
       "users"."reset_password_token"                AS t0_r18,
       "users"."reset_password_sent_at"              AS t0_r19,
       "users"."remember_created_at"                 AS t0_r20,
       "users"."sign_in_count"                       AS t0_r21,
       "users"."current_sign_in_at"                  AS t0_r22,
       "users"."last_sign_in_at"                     AS t0_r23,
       "users"."current_sign_in_ip"                  AS t0_r24,
       "users"."last_sign_in_ip"                     AS t0_r25,
       "users"."authentication_token"                AS t0_r26,
       "users"."created_at"                          AS t0_r27,
       "users"."updated_at"                          AS t0_r28,
       "users"."time_zone"                           AS t0_r29,
       "users"."username"                            AS t0_r30,
       "users"."middle_name"                         AS t0_r31,
       "users"."primary_sport_id"                    AS t0_r32,
       "users"."state"                               AS t0_r33,
       "users"."high_school"                         AS t0_r34,
       "users"."phone"                               AS t0_r35,
       "users"."user_type_id"                        AS t0_r36,
       "users"."agreed_to_terms_and_conditions"      AS t0_r37,
       "users"."agreed_to_information_integrity"     AS t0_r38,
       "users"."agreed_to_content_responsibility"    AS t0_r39,
       "users"."account_type_id"                     AS t0_r40,
       "users"."social_score"                        AS t0_r41,
       "users"."recruit_year"                        AS t0_r42,
       "users"."college_major"                       AS t0_r43,
       "users"."secondary_sport_id"                  AS t0_r44,
       "users"."handedness"                          AS t0_r45,
       "users"."checkdin_id"                         AS t0_r46,
       "users"."allow_twitter_sync"                  AS t0_r47,
       "users"."allow_facebook_sync"                 AS t0_r48,
       "users"."head_coach"                          AS t0_r49,
       "users"."head_coach_email"                    AS t0_r50,
       "users"."has_recruited_others"                AS t0_r51,
       "users"."customer_id"                         AS t0_r52,
       "users"."last_4_digits"                       AS t0_r53,
       "users"."removed_from_listing"                AS t0_r54,
       "users"."slug"                                AS t0_r55,
       "users"."college_minor"                       AS t0_r56,
       "users"."type"                                AS t0_r57,
       "users"."billing_expiration_month"            AS t0_r58,
       "users"."billing_expiration_year"             AS t0_r59,
       "users"."billing_name"                        AS t0_r60,
       "users"."billing_address"                     AS t0_r61,
       "users"."billing_city"                        AS t0_r62,
       "users"."billing_state"                       AS t0_r63,
       "users"."billing_zip"                         AS t0_r64,
       "users"."college_id"                          AS t0_r65,
       "users"."agreed_to_age_requirements"          AS t0_r66,
       "users"."primary_sport_primary_position_id"   AS t0_r67,
       "users"."secondary_sport_primary_position_id" AS t0_r68,
       "users"."recruit_status_id"                   AS t0_r69,
       "users"."active_flag"                         AS t0_r70,
       "users"."public"                              AS t0_r71,
       "invitations"."id"                            AS t1_r0,
       "invitations"."sender_id"                     AS t1_r1,
       "invitations"."role_id"                       AS t1_r2,
       "invitations"."to"                            AS t1_r3,
       "invitations"."accepted_at"                   AS t1_r4,
       "invitations"."token"                         AS t1_r5,
       "invitations"."created_at"                    AS t1_r6,
       "invitations"."updated_at"                    AS t1_r7,
       "invitations"."current_state"                 AS t1_r8,
       "invitations"."requester_id"                  AS t1_r9,
       "invitations"."user_type"                     AS t1_r10,
       "invitations"."type"                          AS t1_r11
FROM   "users"
       INNER JOIN "stats"
               ON "stats"."athlete_id" = "users"."id"
       LEFT OUTER JOIN "invitations"
                    ON "invitations"."requester_id" = "users"."id"
WHERE  "users"."removed_from_listing" = 'f'
       AND "users"."type" IN ( 'Athlete' )
       AND (( "invitations"."current_state" IN ( 'accepted' )
               OR "invitations"."current_state" IS NULL ))
       AND ( users.primary_sport_id = 13
              OR users.secondary_sport_id = 13 )
       AND (( "stats"."stat_type_id" = 22
              AND "stats"."value" > '2.0' ))
       AND (( "stats"."stat_type_id" = 2
              AND "stats"."value" > '10' )) 

これが機能しない理由はありますか?ぶつかった!

::::: UPDATE :::::次のようにして修正しましたが、それでもかなり高速です。

def query
athletes = Athlete.listed.for_sport( self.sport )
relation = athletes

return relation if @conditions.blank?

@conditions = @conditions.map { |k, v| v } if @conditions.is_a?(Hash)

@conditions.each do |condition|
  case condition[:type]
  when "stat"
    if !condition[:q].eql?("")
      relation = case condition[:predicate]
      when /less than/i
        athletes.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.lt (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
      when /greater than/i
        athletes.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.gt (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
      when /equal to/i
        athletes.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.eq (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
      when /not equal to/i
        athletes.joins{stats}.where{(stats.stat_type_id.eq condition[:stat_type_id]) & (stats.value.not_eq (StatType.where(:id => condition[:stat_type_id]).first.display_as_decimal == true ? condition[:q].to_f.to_s : condition[:q].to_i.to_s))}
      end
    end
  when "academic"
    relation
  when "social"
    relation
  end
end

relation
end
4

1 に答える 1

2

2番目のクエリには、次のように終了するWHERE句があります。

 AND (( "stats"."stat_type_id" = 22
              AND "stats"."value" > '2.0' ))
 AND (( "stats"."stat_type_id" = 2
              AND "stats"."value" > '10' ))

stat_type_id同時に2と22に等しくすることはできません。次のような統計テーブルへの2番目の結合が必要になります。

INNER JOIN "stats"
               ON "stats"."athlete_id" = "users"."id"
INNER JOIN "stats" AS s2
               ON "s2"."athlete_id" = "users"."id"
(...)
AND (( "stats"."stat_type_id" = 22
              AND "stats"."value" > '2.0' ))
AND (( "s2"."stat_type_id" = 2
              AND "s2"."value" > '10' ))

動的に結合を実行したくない場合は、次のようなサブクエリを使用できます。

SELECT athlete_id
 FROM stats
 WHERE
 ( "stats"."stat_type_id" = 22
              AND "stats"."value" > '2.0' )
OR ( "s2"."stat_type_id" = 2
              AND "s2"."value" > '10' )
GROUP BY athlete_id
HAVING COUNT(*)=<the number of parameters you want to filter by>

これにより、基準を満たすすべてのアスリートが返されるので、残りのテーブルに参加します。

于 2013-03-18T20:47:51.450 に答える