我无法“翻译”下面的SQL查询到有效的外生查询:如何用Elixir的Ecto Query格式表示该查询?
SELECT *
FROM file_modules
WHERE file_id =
(SELECT f.file_id
FROM files AS f
LEFT JOIN file_modules AS fm ON f.file_id = fm.file_id
WHERE f.storage_id = '20:1:0:86d:1591:c89c:512:de52' AND fm.name = 'bruteforce'
ORDER BY f.version DESC
LIMIT 1)
我认为要走的路是这个查询拆分成两个。以下是我已经试过:
q1 =
File
|> where([f], f.storage_id == ^storage_id)
|> join(:left, [f], fm in FileModule, f.file_id == fm.file_id)
|> where([..., fm], fm.name == ^module_name)
|> order_by([..., fm], desc: fm.version)
|> select([fm], fm.file_id)
|> limit(1)
# q1 works and returns the expected file_id
q2 =
q1
|> subquery()
|> where([fm, fm2], fm.file_id == fm2.file_id) # Here's where I'm stuck
|> preload([..., m], [modules: m])
q1
具有以下Ecto.Query结果:
#Ecto.Query<from f0 in Helix.Software.Model.File,
left_join: f1 in Helix.Software.Model.FileModule, on: f0.file_id == f1.file_id,
where: f0.storage_id == ^(storage_id),
where: f1.name == ^:bruteforce, order_by: [desc: f1.version], limit: 1,
select: f0.file_id>
我的问题似乎与q2
。我应该如何格式化它以便使用来自q1
的 结果作为输入?
在此先感谢。
我相信这个问题是不可知的我的基础架构,但在这里它是:
schema "files" do
field :file_id, ID,
primary_key: true
field :name, :string
field :path, :string
field :software_type, Constant
field :file_size, :integer
field :storage_id, Storage.ID
field :crypto_version, :integer
field :full_path, :string
belongs_to :type, SoftwareType,
foreign_key: :software_type,
references: :software_type,
define_field: false
belongs_to :storage, Storage,
foreign_key: :storage_id,
references: :storage_id,
define_field: false
has_many :modules, FileModule,
foreign_key: :file_id,
references: :file_id,
on_replace: :delete
timestamps()
end
schema "file_modules" do
field :file_id, File.ID,
primary_key: true
field :name, Constant,
primary_key: true
field :version, :integer
belongs_to :file, File,
foreign_key: :file_id,
references: :file_id,
define_field: false,
on_replace: :update
end
由于在评论中提到由Jablanović,它有可能是ORM抽象有时会失败。在这种情况下,是否有可能使用上面的原始sql:
1)为了避免丑陋的字符串连接而强制转换File.ID和Storage.ID类型?
2)返回结果后,将该结果预加载或保存到模式中?
我心目中的界面是一样的东西:
q = "SELECT * FROM files WHERE file_id = $1", ^file_id
file = Repo.get(q) |> Repo.preload()
file.file_id # Returns file id
为每Ecto.Adapters.SQL.query/4的例子,它看起来像我能达到1 2点怎么样?
我的最终目标是使用上面的嵌套SQL查询,同时安全地转换file_id和storage_id,并正确使用%File {}模式,并在file.modules
处加载关联。
请注意,存储过程或视图会给我一个更好的界面,我可以使用fragment
正确投射,但是我觉得在将数据“预加载”到模式中仍然存在问题。
你为什么不单独执行两个查询?你不会损失太多。 –
这就是我现在正在做的,作为解决方法..但是如果不能使用子查询,我最终会受到极大的限制。我确定Ecto支持,所以这是我想出它的工作原理。但是到目前为止,即使在阅读了几篇关于Ecto子查询的文章和指南后,我仍然无法理解它。 –
不幸的是,在过去使用多个ORM之后,我可以说每个人迟早会试图将SQL查询翻译成ORM表达式(命中墙)(https://stackoverflow.com/a/41429995/82592) 。有时,将SQL保持原样,不管是字符串还是某种形式的数据库视图,都可以为您和未来的维护者节省大量浪费时间。 –