2017-07-30 1 views
1

J'ai une table item, qui a une référence de clé étrangère à une table tax. La colonne est tax_id.MySQL: requête JOIN qui obtient tous les éléments avec un champ NULL

J'ai déjà eu l'tax_id comme NOT NULL dans mon schéma, mais je viens de changer cela parce que je veux que ce soit en option, alors maintenant il est NULL DEFAULT NULL dans le schéma.

Cela a casse ma requête. Maintenant, quand je demande des articles et que je rejoins les taxes, je n'ai que celles où les champs tax_id correspondent.

C'est ma requête:

SELECT item.* 
FROM item 
JOIN user_item 
    ON user_item.item_id = item.id 
JOIN tax 
    ON tax.id = item.tax_id 
WHERE user_item.user_id = ? 
    AND item.deleted_at IS NULL 
    AND user_item.deleted_at IS NULL 
    AND tax.deleted_at IS NULL 

Cette requête fonctionne, si on me donne les éléments ci-dessous:

+----+--------+--------------------+-------------+-------+---------------------+------------+------------+ 
| id | tax_id | name    | description | price | created_at   | updated_at | deleted_at | 
+----+--------+--------------------+-------------+-------+---------------------+------------+------------+ 
| 1 |  2 | foo    |    | 1.13 | 2017-07-30 15:20:14 | NULL  | NULL  | 
| 2 | NULL | bar    |    | 0.67 | 2017-07-30 15:20:25 | NULL  | NULL  | 
| 3 | NULL | baz    |    | 1.15 | 2017-07-30 15:22:33 | NULL  | NULL  | 
+----+--------+--------------------+-------------+-------+---------------------+------------+------------+ 

Ensuite, la requête renvoie uniquement l'élément avec id 1. Je veux id 2 et 3 aussi.

Comment puis-je modifier ma requête pour y parvenir? Je comprends le problème de la requête est cette partie: ON tax.id = item.tax_id.

Répondre

2

C'est exactement ce que left join s sont pour:

SELECT item.* 
FROM item 
JOIN user_item 
    ON user_item.item_id = item.id 
LEFT JOIN tax -- Here! 
    ON tax.id = item.tax_id 
WHERE user_item.user_id = ? 
    AND item.deleted_at IS NULL 
    AND user_item.deleted_at IS NULL 
    AND tax.deleted_at IS NULL 
+0

Je vois .. Je ne l'ai pas utilisé avant jointure gauche. J'ai essayé de le modifier, mais j'ai reçu cette erreur: 'sql: Erreur d'analyse sur l'index de colonne 1: convertissant driver.Value tapez (" ") en un int: syntaxe invalide'. Je pense que c'est parce que j'essaie de comparer «NULL» à «INT»? – Lansana

+0

Yup - cela vient probablement du code le ** appelle ** cette requête et tente de convertir une des colonnes dans le résultat en un 'int' (quand la valeur retournée réelle) est un' null' – Mureinik

+0

Ah je vois, oui vous avez raison, c'est un bug de programmation et je devrais utiliser le type 'NullInt64' où j'utilise' int', selon certaines recherches que j'ai faites. Mais la requête elle-même fonctionne correctement. Merci pour la perspicacité! – Lansana

1

Je pense que la meilleure approche est de mettre la condition deleted_at dans la clause on. Si vous voulez NULL valeurs pour correspondre entre les tables, puis l'écrire comme:

SELECT i.* 
FROM item i JOIN 
    user_item ui 
    ON ui.item_id = i.id LEFT JOIN 
    tax t 
    ON NOT (t.id <=> i.tax_id) AND -- ids are the same or both `NULL`. 
     t.deleted_at IS NULL 
WHERE ui.user_id = ? AND 
     i.deleted_at IS NULL AND 
     ui.deleted_at IS NULL ; 
+0

Lorsque j'exécute cette requête, j'obtiens 5 résultats. 2 de chacun de ceux avec le champ "NULL" tax_id, et l'un de celui avec le champ tax_id actuel. Mais j'aime l'idée de déplacer la requête deleted_at, je travaille toujours sur une meilleure syntaxe SQL. – Lansana

+0

Pouces pour la recommandation de deleted_at cependant. Je mettais tout deleted_at dans ma clause 'WHERE', mais il est beaucoup plus logique de le mettre sur les jointures respectives. – Lansana