Przykład Rails raw SQL
Jak mogę przekonwertować ten kod na surowy sql i użyć go w rails? Ponieważ kiedy wdrażam ten kod w heroku, pojawia się błąd limitu czasu żądania.Myślę, że będzie to szybsze, jeśli użyję surowego sql.
@payments = PaymentDetail.joins(:project).order('payment_details.created_at desc')
@payment_errors = PaymentError.joins(:project).order('payment_errors.created_at desc')
@all_payments = (@payments + @payment_errors)
5 answers
Możesz to zrobić:
sql = "Select * from ... your sql query here"
records_array = ActiveRecord::Base.connection.execute(sql)
records_array
będzie to wynik twojego zapytania sql w tablicy, którą możesz iterować.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-12 19:48:23
Wiem, że to stare... Ale dzisiaj miałem ten sam problem i znalazłem rozwiązanie:
Model.find_by_sql
Jeśli chcesz utworzyć instancję wyników:
Client.find_by_sql("
SELECT * FROM clients
INNER JOIN orders ON clients.id = orders.client_id
ORDER BY clients.created_at desc
")
# => [<Client id: 1, first_name: "Lucas" >, <Client id: 2, first_name: "Jan">...]
Model.connection.select_all('sql').to_hash
Jeśli chcesz tylko hash wartości:
Client.connection.select_all("SELECT first_name, created_at FROM clients
WHERE id = '1'").to_hash
# => [
{"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
{"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
]
Result object:
select_all
zwraca obiekt result
. Możesz z nim robić magiczne rzeczy.
result = Post.connection.select_all('SELECT id, title, body FROM posts')
# Get the column names of the result:
result.columns
# => ["id", "title", "body"]
# Get the record values of the result:
result.rows
# => [[1, "title_1", "body_1"],
[2, "title_2", "body_2"],
...
]
# Get an array of hashes representing the result (column => value):
result.to_hash
# => [{"id" => 1, "title" => "title_1", "body" => "body_1"},
{"id" => 2, "title" => "title_2", "body" => "body_2"},
...
]
# ActiveRecord::Result also includes Enumerable.
result.each do |row|
puts row['title'] + " " + row['body']
end
Źródła:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-17 20:14:58
Można zrobić direct SQL, aby mieć jedno zapytanie dla obu tabel. Podam przykład sanitized query, aby mieć nadzieję, że ludzie nie umieszczają zmiennych bezpośrednio w samym łańcuchu znaków (SQL injection danger), mimo że ten przykład nie precyzował potrzeby:
@results = []
ActiveRecord::Base.connection.select_all(
ActiveRecord::Base.send(:sanitize_sql_array,
["... your SQL query goes here and ?, ?, ? are replaced...;", a, b, c])
).each do |record|
# instead of an array of hashes, you could put in a custom object with attributes
@results << {col_a_name: record["col_a_name"], col_b_name: record["col_b_name"], ...}
end
Edit : Jak powiedział Huy, prosty sposób to ActiveRecord::Base.connection.execute("...")
. Innym sposobem jest ActiveRecord::Base.connection.exec_query('...').rows
. I możesz używać natywnych instrukcji prepared, np. jeśli używasz postgres, prepared można wykonać za pomocą raw_connection, prepare, i exec_prepared zgodnie z opisem w https://stackoverflow.com/a/13806512/178651
Możesz także wstawiać surowe fragmenty SQL do zapytań relacyjnych ActiveRecord: http://guides.rubyonrails.org/active_record_querying.html oraz w stowarzyszeniach, zakresach itp. Prawdopodobnie możesz skonstruować ten sam SQL za pomocą zapytań relacyjnych ActiveRecord i możesz robić fajne rzeczy z Arelem, o czym wspomina Ernie w http://erniemiller.org/2010/03/28/advanced-activerecord-3-queries-with-arel / . i, oczywiście istnieją inne Ormy, klejnoty itp.
Jeśli to ma być często używane i dodawanie indeksów nie spowoduje innych problemów z wydajnością / zasobami, rozważ dodanie indeksu w DB dla payment_details.created_at i dla payment_errors.created_at.
Jeśli wiele rekordów, a nie wszystkie rekordy muszą pojawić się na raz, rozważ użycie paginacja:
Jeśli potrzebujesz paginate, rozważ utworzenie widoku w DB najpierw o nazwie payment_records, który łączy tabele payment_details i payment_errors, a następnie mieć model dla widoku (który będzie tylko do odczytu). Niektóre DBs obsługują zmaterializowane widoki, co może być dobrym pomysłem na wydajność.
Rozważmy również sprzęt lub specyfikacje VM na serwerze Rails i serwerze DB, konfiguracja, miejsce na dysku, prędkość sieci/opóźnienie / itp., bliskość itp. I rozważ umieszczenie DB na innym serwerze / maszynie wirtualnej niż aplikacja Rails, jeśli tego nie zrobiłeś itp.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:40
Możesz wykonać surowe zapytanie używając ActiveRecord
. I zaproponuję, aby przejść z bloku SQL
query = <<-SQL
SELECT *
FROM payment_details
INNER JOIN projects
ON projects.id = payment_details.project_id
ORDER BY payment_details.created_at DESC
SQL
result = ActiveRecord::Base.connection.execute(query)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-20 14:13:47
Możesz również mieszać surowy SQL z warunkami ActiveRecord, na przykład, jeśli chcesz wywołać funkcję w warunku:
my_instances = MyModel.where.not(attribute_a: nil) \
.where('crc32(attribute_b) = ?', slot) \
.select(:id)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-02 09:30:46