【问题标题】:MySQL joins with WHERE clauseMySQL 使用 WHERE 子句连接
【发布时间】:2010-07-26 18:30:57
【问题描述】:

我有 2 个查询显示 2 个不同的值,但一个查询的结果是意外的。

查询1:

SELECT SUM(T.amount_reward_user) AS total_grouping
   FROM fem_user_cards UC
       LEFT JOIN fem_transactions T USING(card_number)
       LEFT JOIN fem_company_login FCL 
                        ON T.fem_company_login_id=FCL.fem_company_login_id
   WHERE UC.fem_user_login_id=193 
                      AND FCL.grouping<>0 AND T.from_group=1 AND T.authorised=1
   GROUP BY UC.fem_user_login_id

上面的查询给了我用户 193 的总奖励金额。这里的条件是我从这个查询中得到的奖励金额必须来自从 T.from_group=1 可以看出的组。所以这似乎是正确的。

查询2:

   SELECT SUM(T.amount_reward_user) AS total_grouping 
     FROM fem_transactions T 
LEFT JOIN fem_company_login FCL 
ON T.fem_company_login_id=FCL.fem_company_login_id 
    WHERE T.fem_user_login_id=193 
      AND FCL.grouping<>0 AND T.from_group=1 AND T.authorised=1

在此查询中,即使 T.from_group=1,它也将 T.from_group=0 的奖励金额相加。有谁知道问题出在哪里?

例如:

用户 193 在 A 公司(组外所以 T.from_group=1)以 5 美元购买了东西,并获得了 1 美元的奖励,并以 5 美元从 B 公司购买了另一种产品(组外,所以 T.from_group=0 ) 并再次获得 1 美元的奖励。

我的预期输出是:1

我得到:

查询1:1

查询2:2

我可以简单地使用查询 1,但是当我使用它时我遇到了其他问题,所以我需要了解到底发生了什么!


我的目标是从数据库中获取奖励金额的总和。总和应该是不同的集团公司。也就是说,如果我们有 5 个不同的分组公司并且用户在这 5 个公司中使用他的 Moneycard,我应该得到 5 个不同的总数。如果他在不属于该集团的任何公司使用他的卡,则总数不应包括来自该非集团公司的交易。我有 C++ 代码在事务发生时为数据库提供数据。我的 fem_transactions 表有 company_id、amount_reward_user、fem_user_login_id、from_group(这决定了用户是从组外交易还是从组内交易)、授权等。

我想分别过滤每个组中用户193的消费金额。

我现在了解了 JOINTS 概念,但我需要知道为什么第二个查询中的 t.from_group 被忽略?

【问题讨论】:

  • 您必须发布一些演示问题的示例数据和输出,以及您期望的输出。请编辑您的问题并添加此信息。
  • 我不知道它是否能解决您的问题,但您需要更好地了解左连接和 where 子句。这是特定于 SQL Server 的,但 saame 原则适用于所有数据库:wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN
  • 您应该编辑您的原始帖子,而不是发布回复。此外,我们需要查看一些表模式。我不确定分组如何适应公司的分组。

标签: sql mysql phpmyadmin aggregate-functions


【解决方案1】:

问题是您在 Where 子句中针对左连接右侧的列设置了条件。在这两个查询中,这是And FCL.grouping &lt;&gt; 0。这有效地将 Left Join 更改为 Inner Join,因为您要求 FCL.grouping 值存在且不为零(或 Null)。我认为,您想要的是将该标准移入 On 子句:

第一个查询:

Select Sum(T.amount_reward_user) AS total_grouping
From fem_user_cards UC
    Left Join fem_transactions T Using(card_number)
    Left Join fem_company_login FCL
        On FCL.fem_company_login_id = T.fem_company_login_id
            And FCL.grouping<>0
Where UC.fem_user_login_id=193 
    And T.from_group=1 
    And T.authorised=1
Group By UC.fem_user_login_id

第二次查询

Select Sum(T.amount_reward_user) AS total_grouping
From fem_transactions T
    Left Join fem_company_login FCL
        On FCL.fem_company_login_id = T.fem_company_login_id
            And FCL.grouping<>0
Where UC.fem_user_login_id=193 
    And T.from_group=1 
    And T.authorised=1

在所有这些中尚不清楚的是您要实现的目标。即,如果您不过滤它们,为什么还要在任一查询中使用左连接。如果您确实想要过滤具有 fem_company_login 值且分组值 0 的行,则使用原始查询并将左连接更改为内连接。如果您想过滤分组值 0 或根本没有值的人,请执行以下操作:

Select Sum(T.amount_reward_user) AS total_grouping
From fem_transactions T
    Left Join fem_company_login FCL
        On FCL.fem_company_login_id = T.fem_company_login_id
Where UC.fem_user_login_id=193 
    And T.from_group=1 
    And T.authorised=1
    And ( FCL.PrimaryKeyColumn Is Null Or FCL.grouping <> 0 )

【讨论】:

  • 我不知道where 子句会改变连接的含义。我认为语义是连接的行为就像使用连接条件创建了一个虚拟表,然后将where 子句应用于该虚拟表。你能引用你对行为描述的参考吗?
  • @Jim Garrison - Join 的本质就是这样工作的。当您使用左连接时,您要求左侧的所有项目和右侧的任何匹配项目。如果您随后在右侧表中的列上的 Where 子句中应用过滤器,并且不考虑 Null,则您要求值 A. 存在,B. 不为空并且 C. 匹配条件(即等于、不等于、大于等,取决于操作员)。因此,标准FCL.grouping &lt;&gt; 0 规定必须存在 FCL 中的一行,它必须具有非空分组值,并且该值不得等于 0。
  • @Jim Garrison - 继续,如果您应用的过滤器要求存在左连接右侧的行,那么您实际上是在进行内连接。
  • 你能指出这在规范中的描述吗?我的理解是,虚拟表包含缺失行的数据的空值(与内部联接相反,内部联接根本没有虚拟行)。 where 子句只看到空值,不应该改变连接的含义。如果您能在任何 SQL 规范中找到该描述的位置,那将非常有帮助。
  • @Jim Garrison - 你是正确的,因为左连接中的右表将包含缺失行的 NULLS。 然而,然后您将转身并过滤掉 Where 子句中缺失的行。条件FCL.Grouping &lt;&gt; 0 等价于写作( FCL.Grouping IS NOT NULL And FCL.Grouping &lt;&gt; 0 )。这是由于左连接显示左表中的所有行而仅显示右表中匹配的行这一事实的紧急行为。如果您随后过滤掉不匹配的行,您将拥有与 Inner Join 等效的逻辑。
猜你喜欢
  • 2011-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多