문제

I have 4 tables:

key: id, name

project: id, name

project_key: id, key_id, project_id

project_report: id, status, project_id, key_id

project_c_report: id, status, project_id, key_id, c_id

I want to produce a report using those tables: The output should be:

Key.name, project_report.status, project_c_report.status

I was able to do this by getting all the keys from a project, and loop over them

array = []
project.keys.each do |k|
 p =  ProjectReport.where(keyword_id: k, project_id: p.id).map(&:status)
 c =  ProjectCReport.where(keyword_id: k, project_id: p.id, c_id:1).map(&:status)
 array << {name: k.name, pr: p, pcr: c} 
end
array

The problem is that I am doing a lot of selects and everything is slow, can someone help me please with a better way of doing this.

Thank you

도움이 되었습니까?

해결책

First, create a function in your DataBase. This is just a brief example, and also its done in PostgreSQL but shouldnt difer much from MySQL, SQLServer, etc

Function get_myreport(key_id integer, project_id integer [As many params as you'd like the function to get))

pProject    ALIAS FOR $1;
pKey        ALIAS FOR $2;

BEGIN

CREATE TEMP TABLE IF NOT EXISTS tmp_project_report(id integer, project_name character varying, *All the values you want to see in the report);
TRUNCATE tmp_project_report;

INSERT INTO tmp_project_report(all the columns)
SELECT a.table1_fields, b.table2_fields, c.table3_fields, d.table4_fields, e.table5_fields
FROM table1 a, table2 b, table3 c, table4 d, table5 e
WHERE
a.key = pKey
AND b.project_key = pProject

END;

Then, in your controller's method you call the up the function like this

myFunction = ActiveRecord:Base.connection.execute = "Select get_myreport("param1, param2, etc...")

You will have to make a model where you put all the fields that are on the temp_table you've made, and also you will set the temp_table as the self.table_name

Then, in your view, you'd only have to iterate on your collection and display the values accordingly

@report = TempTable.all

<% @report.each_do |report| %>
  <% report.value1 %>
  <% etc... %>
<% end %>

다른 팁

Figure out the database query, then query the database directly from your model:

def records
  connection = ActiveRecord::Base.connection
  records = connection.select %Q {
    SELECT key.name, project_report.status, project_c_report.status
    FROM ...
    JOIN ...
    ;
  }
  records
end

Here is something you can try if you choose to keep this within Rails (note that the following query is untested and is shown for concept only):

report_data = Project.joins(project_key: :key)
  .joins('left join project_reports on project_keys.project_id = project_reports.project_id and project_keys.key_id = project_reports.key_id 
          left join project_c_reports on project_keys.project_id = project_c_reports.project_id and project_keys.key_id = project_c_reports.key_id')
  .where('project_c_reports.c_id = ?', 1)
  .select('projects.name, project_reports.status as report_status, project_c_reports.status as c_report_status')

This should give you an array of Project objects each including the selected three attributes name, report_status, c_report_status. To get these values in an array of these three elements you could do:

report_data.map { |p| [ p.name, p.report_status, p.c_report_status ] }

The type of join for the query depends on your requirement. Given the index are in place the query should be better compared to how it looks in code!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top