查询操作 #
一、查询基础 #
1.1 基本查询 #
elixir
import Ecto.Query
def list_users do
Repo.all(User)
end
def list_users_query do
query = from(u in User, select: u)
Repo.all(query)
end
1.2 选择字段 #
elixir
def list_user_emails do
from(u in User, select: u.email)
|> Repo.all()
end
def list_user_summaries do
from(u in User, select: %{id: u.id, name: u.name, email: u.email})
|> Repo.all()
end
1.3 选择所有字段 #
elixir
def list_users do
from(u in User)
|> Repo.all()
end
二、条件查询 #
2.1 where子句 #
elixir
def get_active_users do
from(u in User, where: u.active == true)
|> Repo.all()
end
def get_users_by_age(min_age, max_age) do
from(u in User, where: u.age >= ^min_age and u.age <= ^max_age)
|> Repo.all()
end
2.2 多条件 #
elixir
def search_users(opts) do
query = from(u in User)
query = if opts[:name] do
from(u in query, where: ilike(u.name, ^"%#{opts[:name]}%"))
else
query
end
query = if opts[:active] do
from(u in query, where: u.active == ^opts[:active])
else
query
end
Repo.all(query)
end
2.3 in操作 #
elixir
def get_users_by_ids(ids) do
from(u in User, where: u.id in ^ids)
|> Repo.all()
end
2.4 is_nil操作 #
elixir
def get_users_without_email do
from(u in User, where: is_nil(u.email))
|> Repo.all()
end
def get_users_with_email do
from(u in User, where: not is_nil(u.email))
|> Repo.all()
end
2.5 like和ilike #
elixir
def search_by_name(name) do
from(u in User, where: ilike(u.name, ^"%#{name}%"))
|> Repo.all()
end
三、排序 #
3.1 order_by #
elixir
def list_users_ordered do
from(u in User, order_by: [desc: u.inserted_at])
|> Repo.all()
end
def list_users_multi_order do
from(u in User, order_by: [asc: u.name, desc: u.inserted_at])
|> Repo.all()
end
3.2 动态排序 #
elixir
def list_users(opts) do
order = opts[:order] || :inserted_at
direction = opts[:direction] || :desc
from(u in User, order_by: [{^direction, ^order}])
|> Repo.all()
end
四、分页 #
4.1 limit和offset #
elixir
def list_users_paginated(page, per_page) do
offset = (page - 1) * per_page
from(u in User,
limit: ^per_page,
offset: ^offset,
order_by: [desc: u.inserted_at]
)
|> Repo.all()
end
4.2 分页辅助函数 #
elixir
def paginate(query, page, per_page) do
offset = (page - 1) * per_page
from(q in query,
limit: ^per_page,
offset: ^offset
)
end
def list_users(page \\ 1, per_page \\ 10) do
from(u in User, order_by: [desc: u.inserted_at])
|> paginate(page, per_page)
|> Repo.all()
end
4.3 总数计算 #
elixir
def list_users_with_count(page \\ 1, per_page \\ 10) do
query = from(u in User)
total = from(q in query, select: count(q.id)) |> Repo.one()
entries = query |> paginate(page, per_page) |> Repo.all()
total_pages = ceil(total / per_page)
%{
entries: entries,
total: total,
page: page,
per_page: per_page,
total_pages: total_pages
}
end
五、聚合函数 #
5.1 count #
elixir
def count_users do
from(u in User, select: count(u.id))
|> Repo.one()
end
def count_active_users do
from(u in User, where: u.active == true, select: count(u.id))
|> Repo.one()
end
5.2 sum, avg, min, max #
elixir
def user_stats do
from(u in User,
select: %{
total: count(u.id),
avg_age: avg(u.age),
min_age: min(u.age),
max_age: max(u.age)
}
)
|> Repo.one()
end
5.3 group_by #
elixir
def users_count_by_status do
from(u in User,
group_by: u.active,
select: {u.active, count(u.id)}
)
|> Repo.all()
end
def posts_count_by_author do
from(p in Post,
group_by: p.author_id,
select: {p.author_id, count(p.id)},
order_by: [desc: count(p.id)]
)
|> Repo.all()
end
5.4 having #
elixir
def authors_with_many_posts(min_posts) do
from(p in Post,
group_by: p.author_id,
having: count(p.id) > ^min_posts,
select: {p.author_id, count(p.id)}
)
|> Repo.all()
end
六、关联查询 #
6.1 join #
elixir
def posts_with_authors do
from(p in Post,
join: u in User,
on: p.author_id == u.id,
select: %{post: p, author: u}
)
|> Repo.all()
end
6.2 多表关联 #
elixir
def comments_with_post_and_author do
from(c in Comment,
join: p in Post, on: c.post_id == p.id,
join: u in User, on: p.author_id == u.id,
select: %{comment: c, post: p, author: u}
)
|> Repo.all()
end
6.3 left_join #
elixir
def posts_with_comments_count do
from(p in Post,
left_join: c in Comment,
on: c.post_id == p.id,
group_by: p.id,
select: {p, count(c.id)}
)
|> Repo.all()
end
七、预加载 #
7.1 基本预加载 #
elixir
def list_posts_with_comments do
from(p in Post, preload: [:comments])
|> Repo.all()
end
def list_posts_with_author do
from(p in Post, preload: [:author])
|> Repo.all()
end
7.2 多重预加载 #
elixir
def list_posts_full do
from(p in Post, preload: [:author, :comments, :tags])
|> Repo.all()
end
7.3 嵌套预加载 #
elixir
def list_posts_with_comments_and_authors do
from(p in Post, preload: [comments: :author])
|> Repo.all()
end
7.4 条件预加载 #
elixir
def list_posts_with_recent_comments do
from(p in Post,
preload: [
comments: from(c in Comment, where: c.inserted_at > ago(7, "day"))
]
)
|> Repo.all()
end
八、子查询 #
8.1 基本子查询 #
elixir
def users_with_posts do
subquery = from(p in Post, select: p.author_id)
from(u in User, where: u.id in subquery(subquery))
|> Repo.all()
end
8.2 exists子查询 #
elixir
def users_with_published_posts do
from(u in User,
where: exists(from(p in Post, where: p.author_id == u.id and p.published == true))
)
|> Repo.all()
end
九、片段查询 #
9.1 使用fragment #
elixir
def search_by_full_name(name) do
from(u in User,
where: fragment("concat(?, ' ', ?) ilike ?", u.first_name, u.last_name, ^"%#{name}%")
)
|> Repo.all()
end
9.2 原始SQL #
elixir
def execute_raw_sql do
Ecto.Adapters.SQL.query!(Repo, "SELECT * FROM users WHERE age > $1", [18])
end
十、动态查询 #
10.1 动态条件 #
elixir
def search_users(filters) do
query = from(u in User)
query = Enum.reduce(filters, query, fn
{:name, name}, q ->
from(u in q, where: ilike(u.name, ^"%#{name}%"))
{:email, email}, q ->
from(u in q, where: ilike(u.email, ^"%#{email}%"))
{:active, active}, q ->
from(u in q, where: u.active == ^active)
_, q -> q
end)
Repo.all(query)
end
10.2 动态排序 #
elixir
def sort_by(query, field, direction) do
from(q in query, order_by: [{^direction, ^field}])
end
十一、查询组合 #
11.1 union #
elixir
def all_content do
posts = from(p in Post, select: %{id: p.id, title: p.title, type: "post"})
pages = from(p in Page, select: %{id: p.id, title: p.title, type: "page"})
from(q in union(posts, ^pages))
|> Repo.all()
end
11.2 except #
elixir
def users_without_admins do
all_users = from(u in User, select: u.id)
admins = from(u in User, where: u.role == "admin", select: u.id)
from(u in User, where: u.id in ^all_users and u.id not in ^admins)
|> Repo.all()
end
十二、总结 #
12.1 核心操作 #
| 操作 | 说明 |
|---|---|
| from | 创建查询 |
| where | 条件过滤 |
| select | 选择字段 |
| order_by | 排序 |
| limit/offset | 分页 |
| join | 关联查询 |
| preload | 预加载 |
| group_by | 分组 |
12.2 查询模式 #
elixir
from(u in User,
where: u.active == true,
select: u,
order_by: [desc: u.inserted_at],
limit: 10
)
|> Repo.all()
12.3 下一步 #
现在你已经了解了查询操作,接下来让我们学习 关联关系,深入了解数据关联!
最后更新:2026-03-28