如何在Ecto查询中使用Exclusive Or(XOR)?例如,我有一个属于transactions
的{{1}}表。我想知道哪些是"新的交易",构成一个新客户以及哪些是构成经常性客户的旧客户。这些users
也属于transactions
。
我希望在给定某个日期的情况下,查询告诉我自该日期以来有新事务的用户的所有事务,但在此之前从未进行过事务。我应该能够反过来看到用户在特定日期之前有什么交易,而不是之后。在日期之前和之后具有交易的用户应从两者中排除。
很容易获得merchant
transactions
merchant
但现在我需要按用户过滤交易,就好像我按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
字段中对其进行过滤,尽管我遇到了在过滤器中将事务相互比较的相同问题。
我一直在考虑的最后一个选项是获取日期之前的交易清单和日期之后的交易清单。然后按用户过滤,如果用户在两个列表中,则删除这两个事务。
更新1/9/2018:
我能够编写一些SQL来提供inserted_at
SQL语句的功能:
WITH
我不确定这是否是运行此类查询的最有效方式。
答案 0 :(得分:0)
如果我理解正确,您想知道给定的交易是否是用户第一个。如果是这样,如果您的数据库引擎支持它们,您可以使用window functions。
所以你的查询将如下所示:
SELECT id
FROM (
SELECT
id,
COUNT(*) OVER (PARTITION BY user_id) AS count
FROM transactions
) AS q WHERE count = 1;
Ecto没有对窗口函数的原生支持,也不支持从子查询中选择,所以你需要使用它来解决它:
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 == 1