Maison > base de données > tutoriel mysql > Les subtilités des valeurs nulles dans MySQL

Les subtilités des valeurs nulles dans MySQL

PHPz
Libérer: 2024-07-17 09:48:49
original
490 Les gens l'ont consulté

The Intricacies of Null Values in MySQL

Introduction:

Pour ceux qui sont nouveaux sur MySQL, moi y compris, vous pourriez rencontrer des résultats inattendus lorsque vous interrogez une table contenant des valeurs nulles. Dans MySQL, null n'est ni vrai ni faux mais inconnu, et vous ne pouvez pas comparer null avec null sauf si vous utilisez l'opérateur 'IS NULL' ou 'IS NOT NULL'. J'ai trouvé que la façon dont MySQL traite null est non seulement intéressante mais aussi importante à comprendre. Ici, je démontre comment null se comporte en utilisant diverses fonctions MySQL !

Joindre des tables avec des colonnes contenant des valeurs nulles

NULL avec INNER JOIN contre NULL avec LEFT JOIN
Disons qu'il y a deux tables, comme décrit ci-dessous :

Nom de la table : enseignants

id dept_id name
101 1 Shrivell
102 1 Throd
103 1 Splint
104 NULL Spiregrain
105 2 Cutflower
106 NULL Deadyawn

Nom de la table : départements

id name
1 Computing
2 Design
3 Engineering
NULL NULL

Remarquez qu'il y a des valeurs nulles dans la table des enseignants. Que se passerait-il si j'utilisais un INNER JOIN pour combiner ces deux tables ?

SELECT teachers.name, departments.name AS department
FROM teachers INNER JOIN departments
ON (teachers.dept_id = departments.id)

Copier après la connexion

Voici le résultat

+-----------+------------+
| Name      | Department |
+-----------+------------+
| Shrivell  | Computing  |
| Throd     | Computing  |
| Splint    | Computing  |
| Cutflower | Design     |
+-----------+------------+
Copier après la connexion

Remarquez que dans les résultats, vous ne voyez pas les noms de deux enseignants dont les Department_ids sont nuls.

Mais qu'en est-il de l'utilisation d'un LEFT JOIN ? Jetons un coup d'oeil.
Voici la requête dans laquelle j'échange simplement « INNER » contre « LEFT ».

SELECT teachers.name, departments.name AS department
FROM teachers LEFT JOIN departments
ON (teachers.dept_id = departments.id)

Copier après la connexion

Voici le résultat

+------------+------------+
| Name       | Department |
+------------+------------+
| Shrivell   | Computing  |
| Throd      | Computing  |
| Splint     | Computing  |
| Spiregrain | NULL       |
| Cutflower  | Design     |
| Deadyawn   | NULL       |
+------------+------------+
Copier après la connexion

Vous remarquerez que tous les professeurs sont répertoriés. INNER JOIN ne renvoie pas les enregistrements avec des valeurs nulles, contrairement à LEFT JOIN.

POURQUOI ?

Gardez à l'esprit que lorsque vous utilisez l'opérateur d'égalité (=) avec NULL à NULL, le résultat n'est ni vrai ni faux : il est inconnu. Par conséquent, les enregistrements avec des valeurs NULL des deux côtés de la comparaison ne sont pas inclus dans le jeu de résultats lors de l'utilisation de INNER JOIN. Cependant, de par la nature de LEFT JOIN, il sélectionne TOUS les enregistrements de la table de gauche (qui est la table des enseignants dans ce cas), même si le dept_id est nul. Contrairement à INNER JOIN, qui supprimerait ces enregistrements de la liste, LEFT JOIN les conserve.

EXISTE & NULL et IN & NULL

EXISTS et IN ne renvoient pas d'enregistrements avec des valeurs nulles.
Considérons l'exemple où j'ai ces tables.

Nom de la table : clients

customer_id first_name last_name phone_number
1 John Doe 123-456-7890
2 Jane Smith 987-654-3210
3 Alice Johnson NULL
4 Bob Brown 555-555-5555

Nom de la table : clients_2

customer_id first_name last_name phone_number
1 John Doe 123-456-7890
2 Jane Smith NULL
3 Alice Johnson 111-222-3333
4 Bob Brown NULL

Here is a query:
Using EXISTS to check if a name in b_table exists in a_table.

SELECT * FROM customers AS c1
WHERE EXISTS(
SELECT * FROM customers_2 AS c2
WHERE c1.first_name = c2.first_name 
AND c1.last_name = c2.last_name 
AND c1.phone_number = c2.phone_number); 
Copier après la connexion

Using IN to see if name in b_table is in a_table

SELECT *
FROM customers AS c1
WHERE (c1.first_name, c1.last_name, c1.phone_number) IN (
    SELECT c2.first_name, c2.last_name, c2.phone_number
    FROM customers_2 AS c2
);

Copier après la connexion

Both returns the same result

+-------------+------------+-----------+--------------+
| customer_id | first_name | last_name | phone_number |
+-------------+------------+-----------+--------------+
| 1           | John       | Doe       | 123-456-7890 |
+-------------+------------+-----------+--------------+
Copier après la connexion

Notice that records with null values are not returned.

WHY?
Because with EXISTS, you can't link columns that are null. For IN, it ignores null values as if they don't exist. Thus, both treat nulls in the same way: neither returns nulls.

** HOWEVER, it's not the same story with NOT EXISTS and NOT IN when dealing with NULL!**

Let's take a look.
I simply swapped EXISTS for NOT EXISTS.

SELECT * FROM customers AS c1
WHERE NOT EXISTS(
SELECT * FROM customers_2 AS c2
WHERE c1.first_name = c2.first_name 
AND c1.last_name = c2.last_name 
AND c1.phone_number = c2.phone_number);

Copier après la connexion

Here is the result

| customer_id | first_name | last_name | phone_number  |
|-------------|------------|-----------|---------------|
| 2           | Jane       | Smith     | 987-654-3210  |
| 3           | Alice      | Johnson   | [NULL]        |
| 4           | Bob        | Brown     | 555-555-5555  |
Copier après la connexion

Notice that it is returning records with null values. Both Jane and Bob's phone numbers in the customers_2 table are null, but since both phone numbers have values in the customers table, the returned values are not null.

How about using NOT IN?

SELECT *
FROM customers AS c1
WHERE (c1.first_name, c1.last_name, c1.phone_number) NOT IN (
    SELECT c2.first_name, c2.last_name, c2.phone_number
    FROM customers_2 AS c2
);

Copier après la connexion

Here is the result

+-------------+------------+-----------+--------------+
| customer_id | first_name | last_name | phone_number |
+-------------+------------+-----------+--------------+
Copier après la connexion

Nothing is returned!
Why does NOT EXISTS return null values but NOT IN does not? It's because they both treat null differently. NOT EXISTS is simply the opposite of EXISTS. It returns EVERYTHING that is not returned by EXISTS, including nulls.

However, NOT IN returns records that evaluate to TRUE, but in MySQL, null is neither TRUE nor FALSE—it is unknown.

Let's take a look at the record for Jane Smith with Id2.
When NOT IN is used, it compares:
Jane != Jane OR Smith != Smith OR 987-654-3210 != null.

Jane != Jane -> False
Smith != Smith -> False
987-654-3210 != null -> NULL
False or False or Null evaluates to NULL, so the record doesn't get returned!

Here's a little twist:
What if the first name in the customers table does not match the first name in the customers_2 table?

Let’s compare:
Jane Smith 987-654-3210 (from the customers table) and Jack Smith null (from the customers_2 table).

Here is the result

+-------------+------------+-----------+--------------+
| customer_id | first_name | last_name | phone_number |
+-------------+------------+-----------+--------------+
| 2           | Jack       | Smith     | 987-654-3210 |
Copier après la connexion

What? You see Jack! Doesn't NOT IN fail to evaluate null as either false or true, so the record shouldn't be returned?

Let's analyze it:

Jane != Jack -> True
Smith != Smith -> False
987-654-3210 != null -> NULL

True or False or Null actually returns:
True || False -> True
True || NULL -> True
Therefore, the record gets returned!

If you want to understand how true, false, and null are evaluated, here is the link:

https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html#operator_and

As you can see, it can get quite confusing when it comes to comparing null values.

At the end of the day, I think it's best to explicitly compare null values using IS NULL or IS NOT NULL, which returns true or false as shown below.

SELECT * FROM customers AS c1
WHERE EXISTS(
SELECT * FROM customers_2 AS c2
WHERE c1.first_name = c2.first_name 
AND c1.last_name = c2.last_name 
AND c1.phone_number = c2.phone_number OR  (c1.phone_number IS NULL AND c2.phone_number IS NULL));

Copier après la connexion

Conclusion

Handling null values in MySQL can be quite challenging, requiring careful attention when they are present in your database. It's crucial to conduct explicit null checking to clearly define how null values should be treated. By implementing the strategies I mentioned earlier, such as using IS NULL or IS NOT NULL, you can ensure more predictable and accurate query results.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal