Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Abfragen dynamisch in Schienen erstellen

Sie können eine SQL-Abfrage basierend auf Ihrem Hash erstellen. Der allgemeinste Ansatz ist rohes SQL, das von ActiveRecord ausgeführt werden kann .

Hier ist ein Konzeptcode, der Ihnen die richtige Vorstellung vermitteln sollte:

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

Was das bewirkt:

  • query_select gibt an, welche Informationen Sie im Ergebnis haben möchten
  • query_where erstellt alle Suchbedingungen und maskiert die Eingabe, um SQL-Injektionen zu verhindern
  • query_tables ist eine Liste aller Tabellen, die Sie durchsuchen müssen
  • table_name = table.constantize.table_name gibt Ihnen den SQL-Tabellennamen, wie er vom Modell verwendet wird
  • raw_query ist die eigentliche kombinierte SQL-Abfrage aus den obigen Teilen
  • ActiveRecord::Base.connection.execute(raw_query) führt das SQL auf der Datenbank aus

Stellen Sie sicher, dass alle Benutzereingaben in Anführungszeichen gesetzt und korrekt maskiert werden, um SQL-Einschleusungen zu verhindern.

Für Ihr Beispiel sieht die erstellte Abfrage folgendermaßen aus:

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

Dieser Ansatz erfordert möglicherweise zusätzliche Logik zum Zusammenführen verwandter Tabellen. In Ihrem Fall, wenn company und category eine Assoziation haben, müssen Sie so etwas zu query_where hinzufügen

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

Einfacher Ansatz: Sie können für alle abfragbaren Paare von Modellen/Tabellen einen Hash erstellen und dort die entsprechende Join-Bedingung hinterlegen. Dieser Hash sollte selbst für ein mittelgroßes Projekt nicht zu komplex sein.

Harter Ansatz: Dies kann automatisch erfolgen, wenn Sie has_many haben , has_one und belongs_to richtig in Ihren Modellen definiert. Sie können die Zuordnungen eines Modells mit reflect_on_all_associations . Implementieren Sie eine Breath-First-Search oder Depth-First Search Algorithmus und beginnen Sie mit einem beliebigen Modell und suchen Sie nach passenden Assoziationen zu anderen Modellen aus Ihrer json-Eingabe. Starten Sie neue BFS/DFS-Läufe, bis keine nicht besuchten Modelle aus der json-Eingabe übrig sind. Aus den gefundenen Informationen können Sie alle Join-Bedingungen ableiten und diese dann als Ausdrücke im where einfügen -Klausel des Raw-SQL-Ansatzes, wie oben erläutert. Noch aufwendiger, aber auch machbar wäre das Auslesen des schema der Datenbank und verwenden Sie einen ähnlichen Ansatz wie hier definiert, indem Sie nach foreign keys suchen .

Assoziationen verwenden: Wenn alle mit has_many verknüpft sind / has_one , können Sie die Joins mit ActiveRecord handhaben durch Verwendung der joins Methode mit inject auf dem "bedeutendsten" Modell so:

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

Was das bewirkt:

Haftungsausschluss Die genaue Syntax, die Sie benötigen, kann je nach verwendeter SQL-Implementierung variieren.