如何在Ecto查询中使用异或(XOR)?例如,我有一个属于users的transactions表。我想知道哪些是构成新客户的“新交易”,哪些是构成经常性客户的旧交易。这些transactions也属于merchant。
我希望查询在给定某个日期的情况下,告诉我自该日期以来有新事务但在此之前从未有过事务的用户的所有事务。我应该能够反其道而行之,能够看到哪些用户在某个日期之前而不是之后进行了交易。应该将在日期之前和之后有事务的用户排除在两者之外。
很容易获得merchant的所有transactions
def merchant_transactions(merchant_id) do
from t in Transactions,
where: t.merchant_id == ^merchant_id
end但是现在我需要按用户过滤事务,就像是按user_id对它们分组,然后按
#this feels wrong and is wrong, how I compare the records to each other?
def get_transactions_from_new_users(query) do
from t in query,
where: t.user_id == t.user_id,
where: ...
end 它在循环中更有意义:
#Psuedo (Non-SQL) code
users = get all the users for a merchant <- return all users through transactions
for each user, get transactions
if the user has transactions before and after the date, remove them from the list
if the user has transactions before the date, remove them from the list 我感觉像是一个连接,了解它是如何工作的,然后在user_id和inserted_at字段上对其进行过滤,尽管我在过滤器中遇到了将事务彼此进行比较的相同问题。
我一直在考虑的最后一个选项是获取日期之前的交易列表和日期之后的交易列表。然后按用户进行筛选,如果该用户在两个列表中,则删除两个事务。
2018年1月9日更新:
我能够编造一些WITH来提供SQL语句的功能:
WITH new_transactions AS (
select * from transactions
where merchant_id = 1 and inserted_at > date '2017-11-01'
), older_transactions AS (
select * from transactions
where merchant_id = 1 and inserted_at < date '2017-11-01'
)
SELECT * from new_transactions
WHERE user_id NOT IN (select user_id from older_transactions);我不确定这是否是运行这种查询的最有效的方法。
发布于 2018-01-06 03:59:24
如果我理解正确的话,您想知道给定的事务是否为用户优先事务。如果是这样,您可以使用window functions,如果您的DB引擎支持它们的话。
因此您的查询将如下所示:
SELECT id
FROM (
SELECT
id,
COUNT(*) OVER (PARTITION BY user_id) AS count
FROM transactions
) AS q WHERE count = 1;Ecto既不支持窗口函数,也不支持select from subquery,所以你需要使用hack:
counts =
from t in Transaction,
where: t.merchant_id == ^merchant_id
select: %{
id: t.id,
count: fragment("COUNT(*) OVER (PARTITION BY ?)", t.user_id),
}
from t in Transaction,
inner_join: counts in subquery(counts), on: counts.id == t.id,
where: counts.count == 1使用Ecto.OLAP的window-functions分支可以更简单一些(不知羞耻的插件,仍然是WIP)。
counts =
from t in Transaction,
where: t.merchant_id == ^merchant_id
select: %{
id: t.id,
count: window(count(t.id), over: [partition_by: t.user_id]),
}
from t in Transaction,
inner_join: counts in subquery(counts), on: counts.id == t.id,
where: counts.count == 1https://stackoverflow.com/questions/48120124
复制相似问题