我试图使用ecto执行一个查询,并将子查询作为其中一个 SELECT
s. 在SQL中是这样的(player has_many votes
):
SELECT
players.id AS player_id,
(SELECT count(*) FROM votes WHERE votes.player_id = players.id) AS vote_count
FROM
players
然而,根据一个参数的存在,我想用 SELECT
子查询有一个额外的 WHERE
条款。例如
SELECT
players.id AS player_id,
(SELECT count(*) FROM votes WHERE votes.player_id = players.id AND votes.type = 'motm') AS vote_count
FROM
players
在ecto中,我想出了这样的办法。
vote_count_query =
from(p in Player,
select: %{
player_id: p.id,
vote_count:
fragment(
"SELECT count(*) FROM votes WHERE votes.player_id = ?",
p.id
)
}
)
假设有一个变量 vote_type
有无 nil
,我怎么能有条件地添加一个 where
子句到内部选择子查询?例如
fragment(
"SELECT count(*) FROM votes WHERE votes.player_id = ? AND votes.type = ?",
p.id,
^vote_type
)
(如果有更好的方法来获取票数,则可以通过 都 玩家,那么我会很高兴听到。在连接的情况下,似乎没有投票存在的玩家不会被返回)。)
虽然 评语 由 @dogbert 所做的看起来可能会成功,我通过将 SELECT 子查询替换为左连接来实现。
def vote_count(team_id, vote_type \\ nil) do
vote_count_query =
Player
|> select([p, v], %{
player_id: p.id,
vote_count: count(v.id)
})
|> where([p, _], p.team_id == ^team_id)
|> group_by([p, _], p.id)
# depending on whether we are filtering by vote_type use the appropriate join
# condition
if(is_nil(vote_type),
do: vote_count_query |> join(:left, [p], v in assoc(p, :votes)),
else:
vote_count_query
|> join(:left, [p], v in Vote, on: p.id == v.player_id and v.type == ^vote_type)
)
end
看来关键是要使用 左边 在加入条件中加入票数类型的外部加入,而不是默认的内部加入。否则结果中不会返回0票的玩家。