首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在Ecto查询中使用异或(XOR),并在多对多关系中按ID过滤?

如何在Ecto查询中使用异或(XOR),并在多对多关系中按ID过滤?
EN

Stack Overflow用户
提问于 2018-01-06 03:31:07
回答 1查看 155关注 0票数 0

如何在Ecto查询中使用异或(XOR)?例如,我有一个属于userstransactions表。我想知道哪些是构成新客户的“新交易”,哪些是构成经常性客户的旧交易。这些transactions也属于merchant

我希望查询在给定某个日期的情况下,告诉我自该日期以来有新事务但在此之前从未有过事务的用户的所有事务。我应该能够反其道而行之,能够看到哪些用户在某个日期之前而不是之后进行了交易。应该将在日期之前和之后有事务的用户排除在两者之外。

很容易获得merchant的所有transactions

代码语言:javascript
复制
def merchant_transactions(merchant_id) do
  from t in Transactions,
  where: t.merchant_id == ^merchant_id
end

但是现在我需要按用户过滤事务,就像是按user_id对它们分组,然后按

代码语言:javascript
复制
#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  

它在循环中更有意义:

代码语言:javascript
复制
#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_idinserted_at字段上对其进行过滤,尽管我在过滤器中遇到了将事务彼此进行比较的相同问题。

我一直在考虑的最后一个选项是获取日期之前的交易列表和日期之后的交易列表。然后按用户进行筛选,如果该用户在两个列表中,则删除两个事务。

2018年1月9日更新:

我能够编造一些WITH来提供SQL语句的功能:

代码语言:javascript
复制
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);

我不确定这是否是运行这种查询的最有效的方法。

EN

Stack Overflow用户

发布于 2018-01-06 03:59:24

如果我理解正确的话,您想知道给定的事务是否为用户优先事务。如果是这样,您可以使用window functions,如果您的DB引擎支持它们的话。

因此您的查询将如下所示:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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.OLAPwindow-functions分支可以更简单一些(不知羞耻的插件,仍然是WIP)。

代码语言:javascript
复制
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
票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48120124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档