Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Dynamiczne budowanie zapytań w railach

Możesz utworzyć zapytanie SQL na podstawie swojego skrótu. Najbardziej ogólnym podejściem jest surowy SQL, który może być wykonany przez ActiveRecord .

Oto kod koncepcyjny, który powinien dać ci właściwy pomysł:

query_select = "select * from "
query_where = ""
tables = [] # for selecting from all tables
hash.each do |table, values|
  table_name = table.constantize.table_name
  tables << table_name
  values.each do |q|
    query_where += " AND " unless query_string.empty?
    query_where += "'#{ActiveRecord::Base.connection.quote(table_name)}'."
    query_where += "'#{ActiveRecord::Base.connection.quote(q[fieldName)}'"
    if q[:operator] == "starts with" # this should be done with an appropriate method
      query_where += " LIKE '#{ActiveRecord::Base.connection.quote(q[val)}%'"
    end
  end
end
query_tables = tables.join(", ")
raw_query = query_select + query_tables + " where " + query_where 
result = ActiveRecord::Base.connection.execute(raw_query)
result.to_h # not required, but raw results are probably easier to handle as a hash

Co to robi:

  • query_select określa, jakie informacje chcesz uzyskać w wyniku
  • query_where buduje wszystkie warunki wyszukiwania i unika wprowadzania danych, aby zapobiec wstrzykiwaniu SQL
  • query_tables to lista wszystkich tabel, które musisz przeszukać
  • table_name = table.constantize.table_name da ci nazwę tabeli SQL używaną przez model
  • raw_query jest rzeczywistym połączonym zapytaniem sql z powyższych części
  • ActiveRecord::Base.connection.execute(raw_query) wykonuje sql w bazie danych

Upewnij się, że wszystkie dane wprowadzone przez użytkownika zostały umieszczone w cudzysłowie i odpowiednio je zmieniłeś, aby zapobiec wstrzyknięciom SQL.

W twoim przykładzie utworzone zapytanie będzie wyglądać tak:

select * from companies, categories where 'companies'.'name' LIKE 'a%' AND 'companies'.'hq_city' = 'karachi' AND 'categories'.'name' NOT LIKE '%ECommerce%'

Takie podejście może wymagać dodatkowej logiki łączenia powiązanych ze sobą tabel.W twoim przypadku, jeśli company i category masz skojarzenie, musisz dodać coś takiego do query_where

"AND 'company'.'category_id' = 'categories'.'id'"

Łatwe podejście: Możesz utworzyć skrót dla wszystkich par modeli/tabel, które mogą być odpytywane i przechowywać tam odpowiedni warunek złączenia. Ten skrót nie powinien być zbyt skomplikowany, nawet dla projektu średniej wielkości.

Trudne podejście: Można to zrobić automatycznie, jeśli masz has_many , has_one i belongs_to prawidłowo zdefiniowane w Twoich modelach. Powiązania modelu można uzyskać za pomocą reflect_on_all_associations . Zaimplementuj Breath-First-Search lub Depth-First Search algorytm i zacznij od dowolnego modelu i wyszukaj pasujące asocjacje do innych modeli z danych wejściowych json. Rozpocznij nowe uruchamianie BFS/DFS, dopóki nie będzie żadnych nieodwiedzonych modeli z danych wejściowych json. Ze znalezionych informacji możesz wyprowadzić wszystkie warunki złączenia, a następnie dodać je jako wyrażenia w where klauzula surowego podejścia sql, jak wyjaśniono powyżej. Jeszcze bardziej skomplikowane, ale również wykonalne byłoby odczytanie bazy danych schema i używając podobnego podejścia, jak tutaj zdefiniowano, szukając foreign keys .

Korzystanie z skojarzeń: Jeśli wszystkie z nich są powiązane z has_many / has_one , możesz obsłużyć złączenia za pomocą ActiveRecord za pomocą joins metoda z inject na "najważniejszym" modelu takim jak ten:

base_model = "Company".constantize
assocations = [:categories]  # and so on
result = assocations.inject(base_model) { |model, assoc| model.joins(assoc) }.where(query_where)

Co to robi:

  • przekazuje base_model jako dane wejściowe do Enumerable.inject , który będzie wielokrotnie wywoływał input.send(:joins, :assoc) (w moim przykładzie wystarczyłoby to Company.send(:joins, :categories) co jest odpowiednikiem `Company.categories
  • w połączeniu połączonym wykonuje warunki WHERE (zbudowane jak opisano powyżej)

Zastrzeżenie Dokładna składnia, której potrzebujesz, może się różnić w zależności od używanej implementacji SQL.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wybierz punkty z bazy danych mapy według promienia

  2. Jaki jest najlepszy sposób przechowywania Biblii w SQL?

  3. Jak zmienić zestaw znaków z latin1 na UTF8 w MySQL?

  4. Monitorowanie baz danych za pomocą MySQL Enterprise Monitor

  5. MySQL NET Connect 6.7.2 w Visual Studio 2012