Преобразование сложного запроса / подзапроса postgresql в синтаксис Rails activerecord ИЛИ преобразовать массив в отношение активных записей? - PullRequest
0 голосов
/ 12 декабря 2018

Итак, я потратил немного времени на написание этого запроса, а затем выяснил, каким сложным образом он возвращает массив, а не отношение activerecord.DOH.Это не будет проблемой, но мне нужно использовать Ransack для этих результатов, что требует отношения.

Так что, в основном, мне нужно преобразовать это в Rails, используя синтаксис .joins () и .select() но все, что я пробовал ошибки.Я предполагаю, что мне может понадобиться погрузиться в AREL?

ИЛИ, если это может быть легко преобразовано в отношение activerecord с минимальными проблемами с производительностью и сохранением моих столбцов псевдонимов, то это тоже работает!

Любая помощь или совет приветствуется!

find_by_sql("
  SELECT
    subq.*, 
    renewal_date,
    days_until_due,
    renewal_stage_sort,
    (
      CASE
        WHEN renewal_stage_sort IS NOT NULL THEN
          CASE
            WHEN days_until_due > 42 AND renewal_stage_sort >= 1 THEN TRUE
            WHEN days_until_due > 28 AND days_until_due < 43 AND renewal_stage_sort >= 2 THEN TRUE
            WHEN days_until_due > 13 AND days_until_due < 29 AND renewal_stage_sort >= 3 THEN TRUE
            WHEN days_until_due > -1 AND days_until_due < 14 AND renewal_stage_sort >= 4 THEN TRUE
            WHEN days_until_due < 0 AND renewal_stage_sort >= 5 THEN TRUE
            ELSE FALSE
          END
        ELSE FALSE
      END
    )
    AS on_target
  FROM (   
     SELECT DISTINCT ON (renewals.id) renewals.*,
     CASE
       WHEN renewal_types.name = 'IEP-504' THEN patients.iep_renewal_date
       WHEN renewal_types.name = 'RR' THEN patients.rr_date
       ELSE NULL
     END 
     AS renewal_date,
     (  CASE
          WHEN renewal_types.name = 'IEP-504' THEN patients.iep_renewal_date::date
          WHEN renewal_types.name = 'RR' THEN patients.rr_date::date
          ELSE NULL
        END
        - current_date)
     AS days_until_due, 
     renewal_stages.sort_order AS renewal_stage_sort
     FROM renewals
     INNER JOIN renewal_types ON renewal_types.id = renewals.renewal_type_id
     LEFT JOIN renewal_stages ON renewal_stages.id = renewals.renewal_stage_id
     INNER JOIN patients ON patients.id = renewals.patient_id AND patients.deleted_at IS NULL
     WHERE renewals.deleted_at IS NULL
   ) subq
")    

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

Общее решение - использовать .from (subquery_sql), чтобы вы выполняли минимальный объем работы.Затем вы можете извлекать объединения и т. Д. Из подзапроса и в .joins по частям.

User.
  from("(select distinct * from users where id > 0) users ").
  select("users.*, false as mystatus").
  first.
  mystatus 

Поскольку вы хотите ActiveRecord :: Relation, вам нужно использовать правильные методы https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html Если выиспользование Arel напрямую для построения запроса не решит вашу проблему, потому что он не знает о моделях, он просто знает о таблицах, select, group by, параметре запроса и т. д., это низкий уровень.

Вы не сделалине опубликовал вашу схему, поэтому я не проверял, работает ли приведенный ниже код, но что-то вроде этого

fromsql = <<-SQL
(   
SELECT DISTINCT ON (renewals.id) renewals.*,
CASE
  WHEN renewal_types.name = 'IEP-504' THEN patients.iep_renewal_date
  WHEN renewal_types.name = 'RR' THEN patients.rr_date
  ELSE NULL
END 
AS renewal_date,
(  CASE
    WHEN renewal_types.name = 'IEP-504' THEN patients.iep_renewal_date::date
    WHEN renewal_types.name = 'RR' THEN patients.rr_date::date
    ELSE NULL
  END
  - current_date)
AS days_until_due, 
renewal_stages.sort_order AS renewal_stage_sort
FROM renewals
INNER JOIN renewal_types ON renewal_types.id = renewals.renewal_type_id
LEFT JOIN renewal_stages ON renewal_stages.id = renewals.renewal_stage_id
INNER JOIN patients ON patients.id = renewals.patient_id AND patients.deleted_at IS NULL
WHERE renewals.deleted_at IS NULL
) renewals
SQL

select_sql = <<-SQL
  renewals.*, 
  renewal_date,
  days_until_due,
  renewal_stage_sort,
  (
    CASE
      WHEN renewal_stage_sort IS NOT NULL THEN
        CASE
          WHEN days_until_due > 42 AND renewal_stage_sort >= 1 THEN TRUE
          WHEN days_until_due > 28 AND days_until_due < 43 AND renewal_stage_sort >= 2 THEN TRUE
          WHEN days_until_due > 13 AND days_until_due < 29 AND renewal_stage_sort >= 3 THEN TRUE
          WHEN days_until_due > -1 AND days_until_due < 14 AND renewal_stage_sort >= 4 THEN TRUE
          WHEN days_until_due < 0 AND renewal_stage_sort >= 5 THEN TRUE
          ELSE FALSE
        END
      ELSE FALSE
    END
  )
  AS on_target
SQL

Referal.from(fromsql).select(select_sql).to_sql
0 голосов
/ 12 декабря 2018

На самом деле не делает всю работу, но это начало ...

http://www.scuttle.io/

Дает:

RenewalStages.sortOrder.select(
  [
    Subq.arel_table[Arel.star], :renewal_date, :days_until_due, :renewal_stage_sort, Arel::Nodes::Group.new(
      Arel.sql(
        'CASE        WHEN renewal_stage_sort IS NOT NULL THEN          CASE            WHEN days_until_due > 42 AND renewal_stage_sort >= 1 THEN TRUE            WHEN days_until_due > 28 AND days_until_due < 43 AND renewal_stage_sort >= 2 THEN TRUE            WHEN days_until_due > 13 AND days_until_due < 29 AND renewal_stage_sort >= 3 THEN TRUE            WHEN days_until_due > -1 AND days_until_due < 14 AND renewal_stage_sort >= 4 THEN TRUE            WHEN days_until_due < 0 AND renewal_stage_sort >= 5 THEN TRUE            ELSE FALSE          END        ELSE FALSE      END'
      )
    ).as('on_target')
  ]
).where(Renewal.arel_table[:deleted_at].eq(nil))

И да, таблицы Арелапо-видимому, необходимо

...