SQL 个使用自联接的查询

SQL queries using self-join

我可以进行简单的 select、加入、更新查询。但这对我来说似乎有点难(我只是在学习)。

客户有这样的 table(使用 Mysql)(我无法控制他的数据库架构,我无法创建a Customers table 给他。我只需要创建一些客户报告)。

+-----------+--------------+--------------------------+
|Transaction|Customers name|Customers email   |Set    |
+-----------+--------------+--------------------------+
| 1         | John         | jo@gmail.com     | blue  |
| 2         | Mary         | ma@gmail.com     | green |
| 3         | Paul         | pa@gmail.com     | red   |
| 4         | JOHN G.      | jo@gmail.com     | green |
| 5         | Paul Simon   | pa@gmail.com     | blue  |
+-----------+--------------+--------------------------+

如您所见,每笔交易客户都可以自由输入自己的名字。这可能会带来明显更多的客户,但电子邮件字段是独一无二的。

我需要做这些报告(所有这些都是由他购买的东西驱动的 - 'Set' 字段):

1) AND 搜索(如 'blue' AND 'green') 已购买 'this' 和 'that' 套装的客户。 我需要得到这样的结果:

|John      | jo@gmail.com |

或者这个(正如我所说,John 可以在每次交易中以不同的方式输入他的名字。如果电子邮件是唯一的,那很好):

|JOHN G.   | jo@gmail.com |

2) 或搜索(如 'blue' 或 'red') 需要得到这个:

|John      | jo@gmail.com | 
|Paul      | pa@gmail.com |

或者这个:

|John      | jo@gmail.com | 
|Paul Simon| pa@gmail.com |

3) 买了一套,但没买另一套(喜欢 'green' 但不喜欢 'blue')

|Mary      | ma@gmail.com |

有人知道怎么做吗?我相信这可以通过某种 'self join' 来实现。但由于我只是一个初学者,我不知道如何解决这个问题。

对于第一个查询 - 我在这里使用子查询

select name,email from customer c where Set = 'blue' and c.email = (select email from customer where Set = 'green' and email = c.email);

对于第二个查询-简单或条件就足够了

select * from customer where Set = 'green' or Set = 'blue' group by email  ;

对于第三个查询-(它是一种解决方法,根据您的要求它会起作用,它基于这样的方法,比如应该只有 1 条记录并且该记录应该具有输入中提到的设置值)

select * from customer group by email having count(pset)= 1 and pset like 'green';

显然一个人可以买这套或那套,我想一个人甚至有可能在以后的交易中再次购买同一套。

所以你想要每个人的信息。最简单的方法是通过按人分组 (GROUP BY) 来汇总您的数据。然后检查 HAVING 子句中的聚合:Did the customer by set X and/or y?

查询 1:

select email, name
from transactions
group by email
having max(case when set = 'blue' then 1 else 0 end) = 1
   and max(case when set = 'green' then 1 else 0 end) = 1;

查询 2:

select email, name
from transactions
group by email
having max(case when set = 'blue' then 1 else 0 end) = 1
    or max(case when set = 'red' then 1 else 0 end) = 1;

查询 3:

select email, name
from transactions
group by email
having max(case when set = 'green' then 1 else 0 end) = 1
   and max(case when set = 'blue' then 1 else 0 end) = 0;

您通过这些查询获得的姓名只是任意选择的匹配姓名之一。这在 MySQL 中很特别。在标准 SQL 中,这是不允许的。无论如何,无论是 MySQL 还是标准 SQL,您也可以使用 MIN(name)MAX(name) 来始终按字母顺序获取第一个或最后一个。

顺便说一句:CASE WHEN 表达式是标准的 SQL。然而,MySQL 具有额外的特殊布尔处理功能:真表达式的计算结果为 1,假表达式的计算结果为 0。因此在 MySQL 中,您可以简单地编写 max(set = 'green') = 1 而不是 max(case when set = 'green' then 1 else 0 end) = 1.