Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Zapytanie Ecto i niestandardowa funkcja MySQL ze zmienną arnością

ORM są wspaniałe, dopóki wyciek . W końcu wszyscy to robią. Ecto jest młody (np. zyskał tylko umiejętność OR klauzule where razem 30 dni temu ), więc po prostu nie jest wystarczająco dojrzałe, aby opracować API, które uwzględnia zaawansowane gyrationy SQL.

Przeglądając możliwe opcje, nie jesteś sam w zapytaniu. Niemożność zrozumienia list we fragmentach (czy to jako część order_by lub where lub gdziekolwiek indziej) został wymieniony w Ecto nr 1485 , na StackOverflow , na Elixir Forum i to post na blogu . To ostatnie jest szczególnie pouczające. Wiecej o tym za chwile. Najpierw wypróbujmy kilka eksperymentów.

Eksperyment nr 1: Można najpierw spróbować użyć Kernel.apply/3 przekazać listę do fragment , ale to nie zadziała:

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

Eksperyment nr 2: Wtedy być może uda nam się go zbudować za pomocą manipulacji ciągami. Co powiesz na podanie fragment ciąg zbudowany w czasie wykonywania z wystarczającą liczbą symboli zastępczych, aby można go było pobrać z listy:

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

Co dałoby FIELD(id,?,?,?) podane ids = [1, 2, 3] . Nie, to też nie działa.

Eksperyment nr 3: Stworzenie całego, ostatecznego kodu SQL zbudowanego z identyfikatorów, umieszczając surowe wartości identyfikatorów bezpośrednio w złożonym ciągu. Poza tym, że jest okropny, to też nie działa:

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

Eksperyment nr 4: To prowadzi mnie do tego wpisu na blogu, o którym wspomniałem. W nim autor oszukuje brak or_where przy użyciu zestawu predefiniowanych makr opartych na liczbie warunków do połączenia:

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

Chociaż to działa i używa ORM „z ziarnem”, że tak powiem, wymaga posiadania skończonej, możliwej do zarządzania liczby dostępnych pól. To może, ale nie musi, zmienić grę.

Moja rada:nie próbuj żonglować wyciekami ORM. Znasz najlepsze zapytanie. Jeśli ORM go nie zaakceptuje, napisz go bezpośrednio za pomocą surowego SQL i udokumentuj, dlaczego ORM nie działa. Osłoń go za funkcją lub modułem, aby w przyszłości zarezerwować sobie prawo do zmiany jego implementacji. Pewnego dnia, gdy ORM nadrobi zaległości, możesz po prostu ładnie go przepisać bez wpływu na resztę systemu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Filtr MySQL na wielu do wielu

  2. SELECT ze zmiennymi zapytania nie używającymi indeksów

  3. MySqlDB Pythona nie jest aktualizowany wiersz

  4. Jak sprawdzić wartość null dla double, który jest pobierany z bazy danych?

  5. Wstaw obiekty Blob w bazach danych MySql za pomocą php