简体   繁体   中英

SQL queries using self-join

I can make simple select, join, update queries. But this seems a bit hard for me (I'm just learning).

Customer has a table like this (using Mysql ) (I don't have control on his DB schema, I can't create a Customers table for him. I just need to create some customer reports).

+-----------+--------------+--------------------------+
|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  |
+-----------+--------------+--------------------------+

As you can see, each transaction the customer enters freely his name. That could lead to apparently more customers, but email field is unique.

I need to make these reports (all of them are driven by what he bought - the 'Set' field):

1) AND searchs (like 'blue' AND 'green') Customers that have bought 'this' AND 'that' set. I need to get a result like this:

|John      | jo@gmail.com |

or this (as I said, John could enter his name different ways each transaction. If the email is unique, it is fine):

|JOHN G.   | jo@gmail.com |

2) OR searchs (like 'blue' or 'red') Need to get this:

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

or this:

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

3) Bought one set, but not the other (like 'green' but not 'blue')

|Mary      | ma@gmail.com |

Doe anyone know how to do that? I believe this could be accomplished by some kind of 'self join'. But as I'm just a beginner, I couldn't figure out how to solve this.

For first query - I am using sub query here

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

For second query- simple or condition will be enough

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

For Third query- (its a work around, as per your requirement it will work,it is based on approach like there should be only 1 record and that record should have Set value as mentioned int the input)

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

Obviously a person can buy this or that set and I imagine it is even possible that one person buys the same set again in a later transaction.

So you want information per person. The easiest way is to aggregate you data hence by grouping by person ( GROUP BY ). Then you check your aggregates in the HAVING clause: Did the customer by set X and / or y?

Query 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;

Query 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;

Query 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;

The name you get with these queries is just one of the matching names arbitrarily chosen. This is something special in MySQL. In standard SQL this would not be allowed. Anyway, whether MySQL or standard SQL, you could also use MIN(name) or MAX(name) to always get the first or last in alphabetical order.

By the way: The CASE WHEN expressions are standard SQL. MySQL, however, features an additional special boolean handling: a true expression evaluates to 1 and a false expression to 0. So in MySQL you can simply write max(set = 'green') = 1 instead of max(case when set = 'green' then 1 else 0 end) = 1 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM