> For the complete documentation index, see [llms.txt](https://docs.glassworks.tech/sgbdr/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.glassworks.tech/sgbdr/interrogation/010-operations-set.md).

# Opérations de set

## Les opérations de Set

On considère le résultat de chaque phrase `select` une nouvelle table (relation). On peut donc fusionner plusieurs relations en utilisant les opérateurs suivants :

* Union : fusionner deux sets, en gardant tous les tuples uniques provenant des 2 sets
* Intersect : fusionner deux sets, en gardant les tuples qui se trouvent dans les 2 sets
* Except : fusionner deux sets, en gardant les tuples du premier set qui ne se trouvent pas dans le 2ème set

{% hint style="success" %}
Les opérateurs de set sont des outils qui permettent :

* De créer des requêtes plus lisibles (plusieurs requêtes simples, fusionnées)
* D'optimiser nos requêtes : éviter des produits cartésiens énormes, et fusionner le résultat
  {% endhint %}

### Union

Je veux savoir les villes de France où l'on a facturé plus que 1000 € pour l'année 2019 **ou** 2022.

Une façon de traiter cette demande serait de construire deux requêtes simples, et puis retourner l'union entre les 2 sets des résultats.

Par exemple :

```sql
select trim(address_city) as city 
from action 
where year(startUtc) = 2019 and budget > 1000;
/* Retourne 113 lignes avec des doublons */
```

Et :

```sql
select trim(address_city) as city 
from action 
where year(startUtc) = 2022 and budget > 1000;
/* Retourne 1354 lignes avec des doublons */
```

Je peux fusionner les 2 tableaux générés avec l'opérateur `union`, qui traitera les deux tableaux comme des sets. C'est-à-dire, il n'y a pas de doublon !

```sql
(select trim(address_city) as city 
from action 
where year(startUtc) = 2019 and budget > 1000)
union
(select trim(address_city) as city 
from action 
where year(startUtc) = 2022 and budget > 1000);
/* Retourne 787 lignes, sans doublon ! */
```

{% hint style="info" %}
Par défaut, `union` enlève les doublons dans le résultat. En revanche, on peut aussi utiliser `union all` afin de garder les doublons.
{% endhint %}

### Intersection

Je veux modifier ma requête. Je veux connaître les villes dans lesquelles on a facturé plus que 1000 € pour l'année 2019 **et** l'année 2022.

Pour cela, pas besoin de créer une série de conditions complètes ! On a juste à utiliser l'opérateur `intersect`, qui va garder uniquement les tuples qui se trouvent dans les 2 sets.

```sql
(select trim(address_city) as city
from action 
where year(startUtc) = 2019 and budget > 1000)
intersect
(select trim(address_city) as city
from action 
where year(startUtc) = 2022 and budget > 1000);
/* Retourne 43 lignes, sans doublon ! */
```

Il y a donc 43 villes où on a facturé plus que 1000 € sur le deux années.

### Except

Je veux savoir quelles villes ont facturé plus que 1000 € en 2019, mais *pas en 2022*. Il faut donc enlever du premier set toutes les villes qui se trouvent aussi dans le deuxième set.

```sql
(select trim(address_city) as city
from action 
where year(startUtc) = 2019 and budget > 1000)
except
(select trim(address_city) as city
from action 
where year(startUtc) = 2022 and budget > 1000);
/* Retourne 43 lignes, sans doublon ! */
```

## Exercice

Les exercices suivants sont basés sur la base de données SAKILA, une base de données de test fourni par MySQL.

[Récupérez la base SAKILA ici.](https://dev.glassworks.tech:18081/courses/sgbdr/sgbdr-supports/-/tree/main/src/samples/sakila)

### Question 1

Un client vient chercher un film avec l’acteur « Groucho Dunst ». Elle aime les films d’action.

Utilisez l’opérateur `union` afin de présenter une liste de films qui répond à, au moins, un des deux critères.

<details>

<summary>Solution</summary>

95 lignes.

```sql
(select title
from film, film_actor, actor
where 
  film.film_id = film_actor.film_id and 
  actor.actor_id = film_actor.actor_id and 
  actor.first_name = "Groucho" and 
  actor.last_name = "Dunst")
union
(select title
from film, film_category, category
where 
  film.film_id = film_category.film_id and 
  film_category.category_id = category.category_id and 
  category.name = "Action");
```

</details>

### Question 2

Un client vient chercher un film avec l’acteur « Groucho Dunst ». Elle aime les films d’action.

Utilisez l’opérateur `intersect` afin d’afficher uniquement la liste de films d’action avec « Groucho Dunst »

<details>

<summary>Solution</summary>

4 lignes.

```sql
(select title
from film, film_actor, actor
where 
  film.film_id = film_actor.film_id and 
  actor.actor_id = film_actor.actor_id and 
  actor.first_name = "Groucho" and 
  actor.last_name = "Dunst")
intersect
(select title
from film, film_category, category
where 
  film.film_id = film_category.film_id and 
  film_category.category_id = category.category_id and 
  category.name = "Action");
```

</details>

### Question 3

Vous mettez en place une promo pour les films non-adulte. En utilisant l’opérateur `except`, trouvez tous les films qui coûtent moins que 4€ à louer, en excluant ceux du rating « R ». Adaptez votre requête afin d’afficher les prix avec 10% de remise.

<details>

<summary>Solution</summary>

534 lignes.

```sql
(select title, (rental_rate * 0.9) as promo, rating 
from film 
where 
  rental_rate < 4)
except
(select title, (rental_rate * 0.9) as promo, rating 
from film 
where 
  rating = "R");
```

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.glassworks.tech/sgbdr/interrogation/010-operations-set.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
