使用左联接和分组依据-消除重复

时间:2020-07-31 01:05:24

标签: mysql sql sqlperformance

我有2个表,我想将它们合并在一起并将其分组以获得客户成员资格信息。我的代码适用于联接,但是当我尝试对列进行求和和分组时,它开始中断,我不知道为什么。

BASE TABLE : sales_detail 
+-------+-----------+-----------+-----------------------------------------+
|   order_date | transaction_id|   product_cost |  payment_type  |    country
+-------+-----------+-----------+------------------------------------------+
|   10/1     |   12345         |      20       |      mastercard |    usa
|   10/1     |   12345         |      50       |      mastercard |    usa
|   10/5     |  82456          |      50       |      mastercard |    usa
|   10/9     |  64789          |      30       |      visa       |    canada
|   10/15    |  08546          |      20       |      mastercard |    usa
|   10/15    |  08546          |      90       |      mastercard |    usa
|   10/17    |  65898          |       50       |      mastercard |   usa
+-------+-----------+-----------+-------------------------------------+
table : client_information
+-------+-----------+-----------+-------------------+
|   transaction_ID | client_Type|   membership  
+-------+-----------+-----------+----------+
|   12345        |   new         | vip         |
|   12345        |   new         | vip         |
|   82456        |   old         | normal      | 
|   08157        |   old         | vip         |
|   08546        |   old         | normal      |  
|   08546        |   old         | normal      |
|   65898        |   new         | vip         |
|   06587        |   new         | vip         |
+-------+-----------+-----------+-----------+

**我希望输出看起来像这样:**

IDEAL OUTPUT
+-------+-----------+-----------+--------------------------------------------+
|   order_date | transaction_ID |   product_cost |  client_Type|   membership 
+-------+-----------+-----------+--------------------------------------------+
|   10/1     |   12345         |      70       |      new        |   vip     |
|   10/12    |   82456         |      50       |      old        |   normal  |
|   10/15    |   08546         |      110      |      old        |   normal  |
|   10/17    |   65898         |      50       |      new        |   vip  |
+-------+-----------+-----------+--------------------------------------------+

我正在尝试按交易ID汇总产品成本,因此我可以按客户类型或成员资格汇总产品成本,而无需重复,因为每个交易ID都代表一项

这是我使用的代码,但未能将我需要的项目分组:

select t1.order_date ,t1.transaction_ID,sum(t1.product_cost), t2.client_type, t2.membership
from sales_detail  t1
inner join client_information t2 on t1.transaction_ID=t2.transaction_ID 
where t1.payment_type='mastercard' and t1.order_date between '2020-01-02' and'2020-02-15'
and country_of_origin != 'canada'
GROUP BY t1.transaction_ID;

提前谢谢!我是一个初学者,所以仍然学习sql的来龙去脉! (我正在使用蜂巢)

2 个答案:

答案 0 :(得分:0)

正如评论中其他提到的那样,表结构很奇怪,其中client_information表将具有多行。但是,如果是这样的话,那么您需要使用不同的值来避免重复。

您的mysql版本是否支持“ with”子句?我不是mysql用户,但这适用于postgres。您可能需要对mysql稍作调整。

    with client_info as 
    (select distinct transaction_id, client_type, membership
    from client_information
    )
    select s.order_date, s.transaction_id, c.client_type, c.membership, sum(s.product_cost) as total_cost
    from sales_detail s
    join client_info c 
        on c.transaction_id = s.transaction_id
    where s.payment_type = 'mastercard'
    and s.country <> 'canada' --assuming country is always populated
    and --input your date logic
    group by s.order_date, s.transaction_id, c.client_type, c.membership

结果:

    order_date;trans_id;client_type;membership;total_cost

    10/1;12345;new;vip;70

    10/15;8546;old;normal;110

    10/17;65898;new;vip;50

    10/5;82456;old;normal;50

答案 1 :(得分:0)

您无法准确地获得我想您想要的东西,这就是原因。当您保存销售明细行并在客户信息表中创建似乎是1:1的行时,没有任何内容明确指示销售明细中的第一行与客户信息中的第一行匹配,第二行与第二行匹配,等等。这使您可以获得笛卡尔结果,因为唯一的匹配就是ID。现在,方便的是,事务表中的两行都显示相同的ID,类型和成员身份,但是它将永远是具有相同ID但类型/成员身份不同的单个事务吗?我不这么认为,但是您只在行上显示了足够的详细信息来覆盖查询,而不是完整的(可以)。

无论如何,作为用户使用“ WITH”构造在示例中提供的“隔离”功能,无非就是直接在主查询中屏蔽查询。您需要首先从事务中获取DISTINCT组件,然后才能汇总数据。

也就是说,这是不使用“ WITH”上下文的查询。

select
      max( sd.order_date ) Order_Date,
      sd.transaction_id,
      sum( sd.product_cost ) TransactionTotalCost,
      max( ci.client_type ) Client_Type,
      max( ci.membership ) Membership
   from
      sales_detail sd
         JOIN ( select distinct
                      transaction_id,
                      client_type,
                      membership
                   from
                      client_information ) ci
            on sd.transaction_id = ci.transaction_id
   where
          sd.payment_type='mastercard' 
      and sd.order_date between '2020-01-02' and'2020-02-15'
      and sd.country != 'canada'
   group by
      sd.transaction_id

现在,以上方法可以工作,但是我还有其他建议。根据数据的大小,内部JOIN获取所有不同的值,即与您的整个数据获取不同的值,而不仅仅是相关日期。为避免这种情况,我将使此内部查询成为连接到销售明细表的“预查询”结果,以便仅在限定日期之内获得那些交易,从而得到一个较小的集合。然后加入销售明细表。我只建议并假设销售明细表应该在交易ID以及其他索引上都有索引,以优化联接。

最后,为了将来考虑,需要查询日期。使用“ BETWEEN”子句可能会导致一些意外结果。如果您的日期列只是一个日期,那就没问题。但是,如果date字段是日期/时间,则在'2020-01-02'和'2020-02-15'之间进行的查询不一定会获得dateTime为'2020-02-15 14:27:35的交易从下午2时27分开始算是在2020年2月15日凌晨12点00:00暗示了这一点,因此可能会导致记录丢失。我的偏好是执行> =起始日期AND <预定日期之后的天。.您将在查询中看到。

select
      max( sd2.order_date ) Order_Date,
      preQuery.transaction_id,
      sum( sd2.product_cost ) TransactionTotalCost,
      max( preQuery.client_type ) Client_Type,
      max( preQuery.membership ) Membership
   from
      ( select distinct
              sd.transaction_id,
              ci.client_type,
              ci.membership
            from
               sales_detail sd
                  JOIN client_information ci
                     on sd.transaction_id = ci.transaction_id
            where
                   sd.payment_type='mastercard' 
               and sd.order_date >= '2020-01-02' 
               and sd.order_Date < '2020-02-16'
               and sd.country != 'canada'
      ) preQuery
         JOIN sales_detail sd2
            on preQuery.Transaction_ID = sd2.Transaction_ID
   group by
      preQuery.transaction_id

因此,在上方,内部预查询会预先验证有关工资类型,日期范围和非加拿大的所有详细信息。只有这样,它才能返回到实际的销售明细(通过sd2的第二个别名)来获得成本和订单日期的总和。

相关问题