sql >> Databasteknik >  >> RDS >> Mysql

Bygga frågor dynamiskt i skenor

Du kan skapa en SQL-fråga baserat på din hash. Den mest generiska metoden är rå SQL, som kan köras av ActiveRecord .

Här är lite konceptkod som borde ge dig rätt idé:

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

Vad detta gör:

  • query_select anger vilken information du vill ha i resultatet
  • query_where bygger alla sökvillkor och undkommer indata för att förhindra SQL-injektioner
  • query_tables är en lista över alla tabeller du behöver söka efter
  • table_name = table.constantize.table_name ger dig SQL-tabellnamnet som används av modellen
  • raw_query är den faktiska kombinerade sql-frågan från delarna ovan
  • ActiveRecord::Base.connection.execute(raw_query) kör sql på databasen

Se till att sätta alla indata från användare inom citattecken och undvik det korrekt för att förhindra SQL-injektioner.

För ditt exempel kommer den skapade frågan att se ut så här:

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

Detta tillvägagångssätt kan behöva ytterligare logik för att sammanfoga tabeller som är relaterade. I ditt fall, om company och category har en association måste du lägga till något sånt här till query_where

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

Enkelt tillvägagångssätt: Du kan skapa en Hash för alla par av modeller/tabeller som kan frågas och lagra lämpligt sammanfogningsvillkor där. Denna Hash bör inte vara för komplex även för ett medelstort projekt.

Hård strategi: Detta kan göras automatiskt om du har has_many , has_one och belongs_to korrekt definierade i dina modeller. Du kan få en modells associationer med reflect_on_all_associations . Implementera en Breath-First-Search eller Depth-First Search algoritm och börja med valfri modell och sök efter matchande associationer till andra modeller från din json-ingång. Starta nya BFS/DFS-körningar tills det inte finns några obesökta modeller från json-ingången kvar. Från den hittade informationen kan du härleda alla anslutningsvillkor och sedan lägga till dem som uttryck i where klausul i raw sql-metoden som förklarats ovan. Ännu mer komplext, men också genomförbart, skulle vara att läsa databasen schema och använda ett liknande tillvägagångssätt som definieras här genom att leta efter foreign keys .

Använda associationer: Om alla är associerade med has_many / has_one , kan du hantera kopplingarna med ActiveRecord genom att använda joins metod med inject på den "mest betydande" modellen så här:

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

Vad detta gör:

  • den skickar basmodellen som startindata till Enumerable.inject , som upprepade gånger anropar input.send(:joins, :assoc) (för mitt exempel skulle detta göra Company.send(:joins, :categories) vilket motsvarar `Company.categories
  • på den kombinerade kopplingen exekverar den where-villkoren (konstruerade enligt beskrivningen ovan)

Ansvarsfriskrivning Den exakta syntaxen du behöver kan variera beroende på vilken SQL-implementering du använder.



  1. Hur man kombinerar datum från ett fält med tid från ett annat fält - MS SQL Server

  2. Anslut till MySQL-datakällan i PHPStorm

  3. Hämta en bild lagrad som BLOB på en MYSQL DB

  4. MySQL rätt syntax att använda nära '' vid rad 1 fel