Mysql
 sql >> база данни >  >> RDS >> Mysql

Ecto заявка и персонализирана MySQL функция с променлива арност

ORM са прекрасни, докато не изтекат . Всички го правят, в крайна сметка. Ecto е млад (т.е. придобива способност само да OR). където клаузите заедно преди 30 дни ), така че просто не е достатъчно зрял, за да е разработил API, който отчита напреднали SQL обороти.

Проучвайки възможните опции, не сте сами в заявката. Невъзможността за разбиране на списъци на фрагменти (независимо дали като част от order_by или where или някъде другаде) е споменат в Ecto issue #1485 , на StackOverflow , във Elixir форум и това публикация в блог . Последното е особено поучително. Повече за това след малко. Първо, нека опитаме някои експерименти.

Експеримент №1: Човек може първо да опита да използва Kernel.apply/3 за да предадете списъка на fragment , но това няма да работи:

|> order_by(Kernel.apply(Ecto.Query.Builder, :fragment, ^ids))

Експеримент №2: Тогава може би можем да го изградим с манипулация на низове. Какво ще кажете за даването на fragment низ, вграден по време на изпълнение с достатъчно заместители, за да може да изтегли от списъка:

|> order_by(fragment(Enum.join(["FIELD(id,", Enum.join(Enum.map(ids, fn _ -> "?" end), ","), ")"], ""), ^ids))

Което би произвело FIELD(id,?,?,?) даден ids = [1, 2, 3] . Не, това също не работи.

Експеримент №3: Създаване на целия, окончателен SQL, изграден от идентификаторите, поставяне на необработените стойности на ID директно в съставения низ. Освен че е ужасен, той също не работи:

|> order_by(fragment(Enum.join(["FIELD(id,", Enum.join(^ids, ","), ")"], "")))

Експеримент №4: Това ме отвежда до тази публикация в блога, която споменах. В него авторът заобикаля липсата на or_where използване на набор от предварително дефинирани макроси въз основа на броя на условията за събиране:

defp orderby_fragment(query, [v1]) do
  from u in query, order_by: fragment("FIELD(id,?)", ^v1)
end
defp orderby_fragment(query, [v1,v2]) do
  from u in query, order_by: fragment("FIELD(id,?,?)", ^v1, ^v2)
end
defp orderby_fragment(query, [v1,v2,v3]) do
  from u in query, order_by: fragment("FIELD(id,?,?,?)", ^v1, ^v2, ^v3)
end
defp orderby_fragment(query, [v1,v2,v3,v4]) do
  from u in query, order_by: fragment("FIELD(id,?,?,?)", ^v1, ^v2, ^v3, ^v4)
end

Въпреки че това работи и използва ORM, така да се каже, "със зърно", изисква да имате краен, управляем брой налични полета. Това може или не може да промени играта.

Моята препоръка:не се опитвайте да заобикаляте течовете на ORM. Знаете най-добрата заявка. Ако ORM не го приеме, напишете го директно с необработен SQL и документирайте защо ORM не работи. Защитете го зад функция или модул, за да можете да си запазите правото в бъдеще да промените изпълнението му. Един ден, когато ORM настигне, можете просто да го пренапишете добре, без да има ефект върху останалата част от системата.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Максимален брой колони в MySQL таблицата

  2. Комбинирайте две колони в SQL за клауза WHERE

  3. Използване на SQL колона от подизбор в клауза where

  4. Ефективен начин за изброяване на чужди ключове за MySQL таблица?

  5. върнете mysql булев като 'да' или 'не'