Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Truy vấn Ecto và hàm MySQL tùy chỉnh với độ hiếm thay đổi

ORM thật tuyệt vời, cho đến khi chúng rò rỉ . Tất cả đều làm, cuối cùng. Ecto còn trẻ (tức là nó chỉ đạt được khả năng OR nơi các mệnh đề kết hợp với nhau 30 ngày trước ), vì vậy nó chỉ đơn giản là chưa đủ trưởng thành để phát triển một API xem xét các bước chuyển đổi SQL nâng cao.

Khảo sát các tùy chọn khả thi, bạn không đơn độc trong yêu cầu. Không thể hiểu danh sách trong các phân đoạn (cho dù là một phần của order_by hoặc where hoặc bất kỳ nơi nào khác) đã được đề cập trong Ecto issue # 1485 , trên StackOverflow , trên Diễn đàn Elixir và điều này bài đăng trên blog . Sau đó là hướng dẫn cụ thể. Thêm vào đó trong một chút. Trước tiên, hãy thử một số thử nghiệm.

Thử nghiệm số 1: Trước tiên, người ta có thể thử sử dụng Kernel.apply/3 để chuyển danh sách tới fragment , nhưng điều đó sẽ không hoạt động:

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

Thử nghiệm số 2: Sau đó, có lẽ chúng ta có thể xây dựng nó bằng thao tác chuỗi. Làm thế nào về việc cung cấp fragment một chuỗi được tạo sẵn khi chạy với đủ chỗ dành sẵn để nó lấy từ danh sách:

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

Cái nào sẽ tạo ra FIELD(id,?,?,?) đã cho ids = [1, 2, 3] . Không, điều này cũng không hoạt động.

Thử nghiệm số 3: Tạo toàn bộ, SQL cuối cùng được xây dựng từ id, đặt các giá trị ID thô trực tiếp vào chuỗi đã soạn. Ngoài việc kinh khủng, nó cũng không hoạt động:

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

Thử nghiệm số 4: Điều này đưa tôi đến với bài đăng trên blog mà tôi đã đề cập. Trong đó, tác giả hack xung quanh việc thiếu or_where bằng cách sử dụng một tập hợp các macro được xác định trước dựa trên số lượng điều kiện để kết hợp với nhau:

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

Mặc dù điều này hoạt động và sử dụng ORM "với hạt" có thể nói như vậy, nhưng nó yêu cầu bạn phải có một số lượng trường có sẵn hữu hạn, có thể quản lý được. Đây có thể là một yếu tố thay đổi cuộc chơi.

Khuyến nghị của tôi:đừng cố gắng tung hứng những rò rỉ của ORM. Bạn biết truy vấn tốt nhất. Nếu ORM không chấp nhận nó, hãy viết nó trực tiếp bằng SQL thô và ghi lại lý do tại sao ORM không hoạt động. Che chắn nó sau một chức năng hoặc mô-đun để bạn có thể bảo lưu quyền thay đổi cách triển khai nó trong tương lai. Một ngày nào đó, khi ORM bắt kịp, bạn có thể viết lại nó một cách độc đáo mà không ảnh hưởng đến phần còn lại của hệ thống.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PHP PDO MySQL và nó thực sự xử lý các giao dịch MySQL như thế nào?

  2. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException Chèn lỗi mysql

  3. Nhận danh sách các ngày giữa hai ngày

  4. MySQL không sử dụng chỉ mục khi kiểm tra =1, nhưng sử dụng nó với =0

  5. Làm thế nào để cung cấp giá trị được tạo bằng Trigger vào Hibernate ValueObject?