sql >> Database >  >> RDS >> Mysql

Query's dynamisch maken in rails

U kunt een SQL-query maken op basis van uw hash. De meest generieke benadering is onbewerkte SQL, die kan worden uitgevoerd door ActiveRecord .

Hier is wat conceptcode die u het juiste idee zou moeten geven:

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

Wat dit doet:

  • query_select specificeert welke informatie u in het resultaat wilt hebben
  • query_where bouwt alle zoekvoorwaarden op en ontsnapt aan invoer om SQL-injecties te voorkomen
  • query_tables is een lijst van alle tabellen die je nodig hebt om te zoeken
  • table_name = table.constantize.table_name geeft u de SQL-tabelnaam zoals gebruikt door het model
  • raw_query is de daadwerkelijke gecombineerde SQL-query uit de bovenstaande delen
  • ActiveRecord::Base.connection.execute(raw_query) voert de sql uit op de database

Zorg ervoor dat alle door de gebruiker ingediende invoer tussen aanhalingstekens wordt geplaatst en op de juiste manier wordt ontsnapt om SQL-injecties te voorkomen.

Voor uw voorbeeld ziet de gemaakte zoekopdracht er als volgt uit:

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

Voor deze aanpak is mogelijk extra logica nodig om tabellen samen te voegen die gerelateerd zijn. In uw geval, als company en category een associatie hebt, moet je zoiets toevoegen aan de query_where

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

Eenvoudige aanpak: U kunt een hash maken voor alle paren van modellen/tabellen die kunnen worden opgevraagd en de juiste join-voorwaarde daar opslaan. Deze hash zou zelfs voor een middelgroot project niet te ingewikkeld moeten zijn.

Harde aanpak: Dit kan automatisch worden gedaan, als u has_many . heeft , has_one en belongs_to goed gedefinieerd in uw modellen. U kunt de associaties van een model verkrijgen met behulp van reflect_on_all_associations . Implementeer een Breath-First-Search of Depth-First Search algoritme en begin met elk model en zoek naar overeenkomende associaties met andere modellen vanuit uw json-invoer. Start nieuwe BFS/DFS-runs totdat er geen niet-bezochte modellen van de json-invoer meer zijn. Uit de gevonden informatie kunt u alle voorwaarden voor deelname afleiden en deze vervolgens als expressies toevoegen aan de where clausule van de ruwe sql-aanpak zoals hierboven uitgelegd. Nog ingewikkelder, maar ook goed te doen, is het lezen van de database schema en met behulp van een vergelijkbare benadering zoals hier gedefinieerd door te zoeken naar foreign keys .

Associaties gebruiken: Als ze allemaal zijn gekoppeld aan has_many / has_one , kunt u de joins afhandelen met ActiveRecord door gebruik te maken van de joins methode met inject op het "meest significante" model als volgt:

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

Wat dit doet:

  • het geeft het basismodel door als startinvoer aan Enumerable.inject , die herhaaldelijk input.send(:joins, :assoc) zal aanroepen (in mijn voorbeeld zou dit Company.send(:joins, :categories) doen wat gelijk is aan `Bedrijf.categorie
  • op de gecombineerde join voert het de waar-voorwaarden uit (geconstrueerd zoals hierboven beschreven)

Disclaimer De exacte syntaxis die u nodig heeft, kan variëren, afhankelijk van de SQL-implementatie die u gebruikt.



  1. Android ListView:hoe databasequery's in bindView() vermijden? Moet een tot veel relatiegegevens ophalen

  2. Duplicaten verwijderen uit een grote tabel

  3. Is er in Oracle een functie die het verschil tussen twee datums berekent?

  4. Oracle 11g op Mac OS X