Question

J'avais l'habitude d'utiliser les instructions standard mysql_connect (), mysql_query (), etc. pour effectuer des opérations MySQL à partir de PHP. Dernièrement, je suis passé à l’utilisation de la merveilleuse classe MDB2. Parallèlement, j'utilise des instructions préparées, de sorte que je n'ai pas à craindre d'échapper à mes attaques d'entrée et d'injection SQL.

Cependant, je rencontre un problème. J'ai une table avec quelques colonnes VARCHAR, spécifiées comme non-null (c'est-à-dire, n'autorisent pas les valeurs NULL). En utilisant les anciennes commandes MySQL PHP, je pouvais faire des choses comme ceci sans problème:

INSERT INTO mytable SET somevarchar = '';

Maintenant, cependant, si j'ai une requête comme celle-ci:

INSERT INTO mytable SET somevarchar = ?;

Et puis en PHP, j'ai:

$value = "";
$prepared = $db->prepare($query, array('text'));
$result = $prepared->execute($value);

Cela générera l'erreur ": la valeur null enfreint la contrainte non nulle" "

.

En guise de solution temporaire, je vérifie si $ value est vide et le modifie en " "" (un seul espace), mais c'est un piratage horrible qui pourrait causer d'autres problèmes.

Comment suis-je censé insérer des chaînes vides avec des instructions préparées sans essayer d'insérer une valeur NULL?

MODIFIER: le projet est trop volumineux pour parcourir l'intégralité de ma base de code. Recherchez partout où une chaîne vide est utilisée. " et le changer pour utiliser NULL à la place. Ce que j'ai besoin de savoir, c'est pourquoi les requêtes MySQL standard traitent " " et NULL en tant que deux choses distinctes (ce qui, à mon avis, est correct), mais les instructions préparées convertissent """ dans NULL.

Notez que " " et NULL ne sont pas la même chose. Par exemple, SELECT NULL = " ;; renvoie NULL au lieu de 1 comme prévu.

Était-ce utile?

La solution

Cela ressemble à un problème lié à l’API MDB2 qui consiste à falsifier la sémantique de frappe de PHP. Comme la chaîne vide en PHP équivaut à NULL, MDB2 la traite probablement comme telle. La solution idéale serait de trouver une solution de contournement au sein de son API, mais je ne la connais pas trop.

Une chose à considérer cependant est qu'une chaîne vide en SQL n'est pas une valeur NULL. Vous pouvez les insérer dans les lignes déclarées 'NOT NULL' très bien:

mysql> CREATE TABLE tbl( row CHAR(128) NOT NULL );
Query OK, 0 rows affected (0.05 sec)

mysql> INSERT INTO tbl VALUES( 'not empty' ), ( '' );
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT row, row IS NULL FROM tbl;
+-----------+-------------+
| row       | row IS NULL |
+-----------+-------------+
| not empty |           0 | 
|           |           0 | 
+-----------+-------------+
2 rows in set (0.00 sec)

mysql> INSERT INTO tbl VALUES( NULL );
ERROR 1048 (23000): Column 'row' cannot be null

Si vous ne parvenez pas à trouver (ou à mettre en œuvre) une solution de contournement dans l'API MDB2, une solution compliquée (bien que légèrement meilleure que celle que vous utilisez actuellement) consiste à définir un variable utilisateur pour la chaîne vide -

SET @EMPTY_STRING = "";
UPDATE tbl SET row=@EMPTY_STRING;

Enfin, si vous devez utiliser la chaîne vide dans une instruction INSERT mais que vous vous trouvez incapable de le faire, la valeur par défaut des types de chaîne dans MySQL est une chaîne vide. Donc, vous pouvez simplement omettre la colonne de l'instruction INSERT et elle sera automatiquement définie sur la chaîne vide (à condition que la colonne ait une contrainte NOT NULL).

Autres conseils

Grâce à certaines réponses, j’ai réalisé que le problème pouvait provenir de l’API MDB2, et non des commandes PHP ou MYSQL proprement dites. Effectivement, je l’ai trouvé dans la FAQ MDB2:

  
      
  • Pourquoi les chaînes vides finissent-elles par NULL dans la base de données? Pourquoi ai-je un NULL   non autorisé dans les champs de texte NOT NULL   Même si la valeur par défaut est """      
        
    • Le problème est que pour certains SGBDR (notamment Oracle), un   la chaîne est NULL. Donc MDB2   fournit une option de portabilité pour   appliquer le même comportement à tous   SGBDR.
    •   
    • Toutes les options de portabilité étant activées par défaut, vous aurez   désactiver la fonctionnalité si vous ne le faites pas   vouloir avoir ce comportement:   $ mdb2- > setOption ('portabilité',   MDB2_PORTABILITY_ALL ^   MDB2_PORTABILITY_EMPTY_TO_NULL);
    •   
  •   

Merci à tous ceux qui ont fourni des réponses réfléchies.

Je réalise que la question est à peu près résolue et a pris sa retraite, mais je l’ai trouvée en cherchant des réponses à une situation similaire et je ne peux pas résister à l'idée de jeter mon chapeau dans le ring.

Sans savoir ce que le NULL / """ colonne se rapporte à, je ne peux pas savoir comment la vraie signification d'une chaîne vide. Une chaîne vide signifie-t-elle quelque chose en soi (par exemple, si je convaincais un juge de me laisser changer mon nom simplement par rien, je serais vraiment irrité si mon nom apparaissait sur mon permis de conduire comme NULL. Mon nom serait!

Cependant, la chaîne vide (ou vide, ou le néant QUELQUE CHOSE, pas simplement le manque de quelque chose (comme NULL)) pourrait également simplement signifier "NOT NULL". ou "Rien, mais toujours pas Null". Vous pouvez même aller dans l’autre direction et suggérer que l’absence de la valeur NULL rend encore MOINS quelque chose que Null, car au moins Null a un nom que vous pouvez prononcer à haute voix!

Mon problème est que, si la chaîne vide est une représentation directe de certaines données (comme un nom ou ce que je préfère être inséré entre les numéros de mon numéro de téléphone, etc.), vous avez le choix entre Sore pour l’utilisation légitime de chaîne vide ou pour utiliser quelque chose qui représente une chaîne vide qui n’est pas NULL (comme un caractère de contrôle ASCII ou un équivalent unicode, une valeur de regex, Jeton totalement inutilisé, tel que: & # 9688;

Si la cellule vide signifie simplement NON NULL, vous pouvez penser à un autre moyen de l'exprimer. Une phrase idiote et évidente est la phrase "Non NULL". Mais j’ai l’impression que NULL signifie quelque chose comme "Ne fait pas partie de ce groupe" alors que la chaîne vide signifie quelque chose comme "ce mec est cool, il n'a tout simplement pas encore eu son tatouage de gang". Dans ce cas, je proposerais un terme / nom / idée pour cette situation, comme "défaut". ou "recrue" ou "en attente".

Maintenant, si, par hasard, vous voulez réellement que les chaînes vides représentent ce qui n'est même pas digne de NULL, créez à nouveau un symbole plus significatif, comme "-1". ou " SUPERNULL " ou "UGLIES".

Dans le système des castes indiennes, les castes les plus basses sont Shudra: agriculteurs et ouvriers. Sous cette caste se trouvent les Dalits: "Les Incorruptibles". Ils ne sont pas considérés comme une caste inférieure, car les considérer comme la caste la plus basse serait considéré comme une contamination de l’ensemble du système.

Alors ne m'appelez pas comme un fou pour penser que des chaînes vides peuvent être pire que NULL!

'Jusqu'à la prochaine fois.

J'ai trouvé la solution!

MDB2 convertit les chaînes vides en chaînes NULL car l'option de portabilité MDB2_PORTABILITY_EMPTY_TO_NULL est activée par défaut (grâce à Oracle qui considère les chaînes vides comme nulles).

Désactivez ces options lorsque vous vous connectez à la base de données:

$options = array(
    'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL
);
$res= & MDB2::connect("mysql://user:password@server/dbase", $options);

Alors que 0 et les chaînes vides sont des variables, NULL est l’absence de données. Et croyez-moi, il est beaucoup plus facile d'écrire une requête à

SELECT * dans la table où tout est NULL que d'essayer de rechercher des chaînes vides: /

Un ensemble de guillemets vides, "" " ne le fait-il pas?

Je suis confus. On dirait que vous utilisez mysqli OO (à partir des balises et du style), mais la syntaxe est différente de celle du manuel sur php.net, qui dit de le faire à la place:

$query = "INSERT INTO mytable SET somevarchar = ?";
$value = "";
$prepared = $db->prepare($query);
$prepared->bind_param("s", $value);
$result = $prepared->execute();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top