sql >> Databáze >  >> RDS >> Mysql

Dynamické vytváření dotazů v kolejích

Můžete vytvořit SQL dotaz na základě vašeho hashe. Nejobecnějším přístupem je nezpracovaný SQL, který lze spustit pomocí ActiveRecord .

Zde je nějaký koncepční kód, který by vám měl poskytnout správnou představu:

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 dělá:

  • query_select určuje, jaké informace chcete mít ve výsledku
  • query_where vytvoří všechny podmínky vyhledávání a opustí vstup, aby zabránil injekcím SQL
  • query_tables je seznam všech tabulek, které potřebujete prohledávat
  • table_name = table.constantize.table_name vám poskytne SQL název_tabulky, jak jej používá model
  • raw_query je skutečný kombinovaný dotaz SQL z výše uvedených částí
  • ActiveRecord::Base.connection.execute(raw_query) spustí sql v databázi

Ujistěte se, že každý vstup odeslaný uživatelem vložíte do uvozovek a správně jej uzavřete, abyste zabránili vkládání SQL.

Pro váš příklad bude vytvořený dotaz vypadat takto:

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

Tento přístup může vyžadovat další logiku pro spojování tabulek, které spolu souvisí. Ve vašem případě, pokud company a category máte přidružení, musíte něco takového přidat do query_where

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

Snadný přístup: Můžete vytvořit hash pro všechny páry modelů/tabulek, které lze dotazovat, a uložit tam příslušnou podmínku spojení. Tento hash by neměl být příliš složitý ani pro středně velký projekt.

Tvrdý přístup: To lze provést automaticky, pokud máte has_many , has_one a belongs_to správně definované ve vašich modelech. Asociace modelu můžete získat pomocí reflect_on_all_associations . Implementujte Breath-First-Search nebo Depth-First Search algoritmus a začněte s jakýmkoli modelem a vyhledejte odpovídající asociace s jinými modely ze svého vstupu json. Spusťte nové běhy BFS/DFS, dokud nezůstanou žádné nenavštívené modely ze vstupu json. Z nalezených informací můžete odvodit všechny podmínky spojení a poté je přidat jako výrazy v where klauzule přístupu raw sql, jak je vysvětleno výše. Ještě složitější, ale také proveditelné by bylo čtení databáze schema a pomocí podobného přístupu, jak je zde definován, vyhledáním foreign keys .

Použití přidružení: Pokud jsou všechny spojeny s has_many / has_one , můžete spojení zpracovat pomocí ActiveRecord pomocí joins metodou inject na "nejvýznamnějším" modelu, jako je tento:

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

Co to dělá:

  • předá základní_model jako počáteční vstup do Enumerable.inject , který bude opakovaně volat input.send(:joins, :assoc) (pro můj příklad by to udělalo Company.send(:joins, :categories) což je ekvivalentní k `Společnost.kategorie
  • při kombinovaném spojení provede podmínky where (vytvořené podle popisu výše)

Odmítnutí odpovědnosti Přesná syntaxe, kterou potřebujete, se může lišit v závislosti na implementaci SQL, kterou používáte.



  1. Uložte data v metodě onDestroy aktivity

  2. vložit do tabulky vyberte max(název_sloupce)+1

  3. MySQLd se po upgradu vaření z 5.6 na 5.7 nespustí

  4. 4 způsoby, jak najít řádky, které obsahují velká písmena v PostgreSQL