Соединение запроса Rails с количеством внутренних таблиц - PullRequest
1 голос
/ 17 июня 2020

У меня есть две таблицы:

Player --> has_many FantasyStarts

FantasyStarts --> belongs_to Player

На английском sh, я пытаюсь найти все SeasonStats за последний год и неделю, которые были первой записью для этого игрока во всей таблице (ie, которые стартовали на прошлой неделе, и это был их первый «старт», когда-либо записанный в таблице). Я построил простой запрос sql, который отлично работает, но я пытаюсь улучшить свои навыки запроса рельсов:

FantasyStart.includes(:player).find_by_sql("with count_table as (select player_id, count(*) as num_starts from fantasy_starts where position != 'BN' group by player_id) select * from fantasy_starts join count_table on fantasy_starts.player_id = count_table.player_id where week = 13 and year = 2019 and count_table.num_starts = 1 and position != 'BN' ")

Я также придумал «рельсовый способ» создания карты подсчетов. будет присоединяться к:

FantasyStart.where.not(position: 'BN').group(:player_id).count

, что дает:

=> {184=>2, 2562721=>5, 2540215=>12, 100004=>57, 100001=>26, 100006=>62, 2505785=>5, 2561029=>1, 2541316=>1, 2558954=>1, 2552408=>12, 2532820=>60, 2507999=>25, 2506194=>16, 2505600=>18, 2532977=>6, 2507164=>75, 2495441=>4, 100022=>23, 2543704=>2, 2532807=>1, 81288=>1, 2550658=>4, 2506386=>15, 2560809=>11, 2533349=>4, 2560735=>3, 2557976=>19, 2556521=>15,....

гипотетически я мог бы использовать карту выше для фильтрации основного запроса и включать только player_ids, которые имеют счетчик 1 на этой карте .

есть хорошие идеи для следующего шага?

Ответы [ 2 ]

1 голос
/ 17 июня 2020

Отвечая на ваш ответ;

Это потому, что вы связываете pluck со своим «вложенным» запросом, таким образом ActiveRecord не может выполнить подзапрос, а вместо этого выполняет другой запрос и используйте результат этого, который представляет собой массив для использования с предложением IN.

Попробуйте вместо этого удалить отрыв, оставив только select:

FantasyStart.where(week: 13, year: 2019).where.not(position: 'BN').where(player_id: FantasyStart.where.not(position: 'BN').group(:player_id).having('count(*) = 1').select(:player_id))

Он должен сгенерировать что-то вроде этого:

SELECT fantasy_starts.*
FROM fantasy_starts
WHERE fantasy_starts.week = $1
AND fantasy_starts.year = $2
AND fantasy_starts.position != $3
AND fantasy_starts.player_id IN (
  SELECT fantasy_starts.player_id
  FROM fantasy_starts
  WHERE fantasy_starts.position != $4
  GROUP BY fantasy_starts.player_id
  HAVING (count(*) = 1)
) [[week, 13], [year, 2019], [position, BN], [position, BN]]

Кажется, вы могли бы сократить запрос, удалив != из подзапроса:

FantasyStart
  .where.not(position: 'BN')
  .where(player_id: FantasyStart
                      .group(:player_id)
                      .having('count(*) = 1')
                      .select(:player_id), week: 13, year: 2019)
0 голосов
/ 17 июня 2020

эй, я думаю, мне стало интересно, что может подумать один из вас, более опытных людей:

FantasyStart.where(week: 13, year: 2019).where.not(position: 'BN').where(player_id: FantasyStart.select(:player_id).where.not(position: 'BN').group(:player_id).having('count(*) = 1').pluck(:player_id))

это генерирует:

(8.4ms) SELECT "fantasy_starts"."player_id" FROM "fantasy_starts" WHERE "fantasy_starts"."position" != $1 GROUP BY "fantasy_starts"."player_id" HAVING (count(*) = 1) [["position", "BN"]]

FantasyStart Load (2.4ms) SELECT "fantasy_starts".* FROM "fantasy_starts" WHERE "fantasy_starts"."week" = $1 AND "fantasy_starts"."year" = $2 AND "fantasy_starts"."position" != $3 AND "fantasy_starts"."player_id" IN ($4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $50, $51, $52, $53, $54, $55, $56, $57, $58, $59, $60, $61, $62, $63, $64, $65, $66, $67, $68, $69, $70, $71, $72, $73, $74, $75, $76, $77, $78, $79, $80, $81, $82, $83, $84, $85, $86, $87, $88, $89, $90, $91, $92, $93, $94, $95, $96, $97, $98, $99, $100, $101, $102, $103, $104, $105, $106, $107, $108, $109, $110, $111, $112, $113, $114, $115, $116, $117, $118, $119) LIMIT $120

это все еще два запроса, так что я знаю это могло быть лучше ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...