MySQL lädt NULL-Werte in numerische Spalten

8

MySQL 5.6.23, InnoDB

Ich LOAD DATA INFILElade Tabellen aus durch Zeichen getrennten Textdateien mit dem Befehl und möchte, dass jedes Feld mit einem \N, das das NULLZeichen in dieser Einstellung ist, ein NULLin die Tabelle einfügt . Einige numerische Typen haben dieses Verhalten, während andere a 0. Ich verwende FIELDS TERMINATED BYund einige Spalten erhalten richtig NULLWerte, so dass es kein Problem mit dem Format fester Zeilen ist.

Dies sind die Typen, die ich beim Testen beobachtet habe:

  • INTEinsätze NULLs
  • DECIMAL(x,0)Einsätze NULLs
  • DECIMAL(x,y)Einsätze 0.0s
  • FLOATEinsätze 0s
  • DOUBLE(x,y)Einsätze 0.0s
  • DOUBLEEinsätze 0s

Alle fraglichen Spalten sind mit definiert DEFAULT NULL. Ich weiß, dass verschiedene Funktionen diese 0s in NULLs umwandeln können . Die Frage ist, ob es einen Datentyp gibt, der mit Dezimalgenauigkeit umgehen kann und auch NULLs beim Laden einfügt.

Außerdem sehe ich eine ganze Reihe von Fragen zum Missverständnis des Unterschieds zwischen einer Zeichenfolge, einer leeren Zeichenfolge und einem Nullwert. ( Beispiel Beispiel Beispiel ) Dies ist nicht das Problem, da die NULLs vorhanden sind und ordnungsgemäß in dieselbe Spalte geladen werden, wenn ich sie als DECIMAL (x, 0) neu definiere, und dann falsch, wenn sie als DECIMAL (x, 3) definiert werden.

WAF
quelle

Antworten:

5

Sehr kurze Antwort: Es wurden keine neuen Datentypen für Sie erstellt.

Während wir uns mit diesem Thema befassen

Versuchen wir es mit einfachem SQL

USE test
DROP TABLE IF EXISTS numtest;
CREATE TABLE numtest
(
  id int not null auto_increment,
  xx decimal(10,3) default null,
  primary key (id)
);
INSERT INTO numtest (id) values (0),(0),(0),(0),(0);
SELECT * FROM numtest;

Funktioniert das ???

mysql> USE test
Database changed
mysql> DROP TABLE IF EXISTS numtest;
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE numtest
    -> (
    ->   id int not null auto_increment,
    ->   xx decimal(10,3) default null,
    ->   primary key (id)
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO numtest (id) values (0),(0),(0),(0),(0);
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM numtest;
+----+------+
| id | xx   |
+----+------+
|  1 | NULL |
|  2 | NULL |
|  3 | NULL |
|  4 | NULL |
|  5 | NULL |
+----+------+
5 rows in set (0.00 sec)

mysql>

OK, gut. Es funktioniert mit SQL. Sie fragen nachLOAD DATA INFILE

Sie haben einen Beitrag aufgerufen, den ich beantwortet habe: MySQL fügt "" als 0 in Dezimalfelder ein. Wie kann man das aufhalten?

Mal sehen, ob dieser Fehler behoben wurde, seit er gesendet wurde. Ich werde versuchen, den Code in diesem Fehler zu duplizieren, der nicht funktioniert hat.

Lassen Sie uns zuerst diese Tabelle aus dem Fehlerbericht erstellen

mysql> USE test
Database changed
mysql> DROP TABLE IF EXISTS bug_repeat;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CREATE TABLE bug_repeat
    -> (
    ->   name varchar(10),
    ->   price decimal(12,6)
    -> )
    -> ENGINE=MYISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW CREATE TABLE bug_repeat\G
*************************** 1. row ***************************
       Table: bug_repeat
Create Table: CREATE TABLE `bug_repeat` (
  `name` varchar(10) COLLATE ascii_bin DEFAULT NULL,
  `price` decimal(12,6) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin
1 row in set (0.00 sec)

mysql>

Als nächstes machen wir einige Daten

C:\>type C:\MySQLDBA\bug_test.txt
name,
name,0
,
name,6
name,2
name,
name,0
name,0
name,
name,0

C:\>

Lassen Sie uns die LOAD DATA INFILE ausführen

mysql> load data local infile 'C:/MySQLDBA/bug_test.txt'
    -> into table test.bug_repeat
    -> fields terminated by ','
    -> lines terminated by '\n';
Query OK, 10 rows affected, 4 warnings (0.00 sec)
Records: 10  Deleted: 0  Skipped: 0  Warnings: 4

Autsch, was ist passiert?

mysql> show warnings\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 1lue: '
*************************** 2. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 3lue: '
*************************** 3. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 6lue: '
*************************** 4. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 9lue: '
4 rows in set (0.00 sec)

mysql> select * from bug_repeat;
+------+----------+
| name | price    |
+------+----------+
| name | 0.000000 |
| name | 0.000000 |
|      | 0.000000 |
| name | 6.000000 |
| name | 2.000000 |
| name | 0.000000 |
| name | 0.000000 |
| name | 0.000000 |
| name | 0.000000 |
| name | 0.000000 |
+------+----------+
10 rows in set (0.00 sec)

mysql>

Was ist der sql_mode?

mysql> select @@sql_mode;
+------------------------+
| @@sql_mode             |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
1 row in set (0.00 sec)

mysql>

Lassen Sie uns den sql_mode ausblenden, die Tabelle abschneiden und neu laden

mysql> set sql_mode = '';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|            |
+------------+
1 row in set (0.00 sec)

mysql> truncate table bug_repeat;
Query OK, 0 rows affected (0.00 sec)

mysql> load data local infile 'C:/MySQLDBA/bug_test.txt'
    -> into table test.bug_repeat
    -> fields terminated by ','
    -> lines terminated by '\n';
Query OK, 10 rows affected, 4 warnings (0.02 sec)
Records: 10  Deleted: 0  Skipped: 0  Warnings: 4

mysql> show warnings\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 1lue: '
*************************** 2. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 3lue: '
*************************** 3. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 6lue: '
*************************** 4. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 9lue: '
4 rows in set (0.00 sec)

mysql>

Lassen Sie die Eingabedatei \Nwie im Fehlerbericht behandeln

C:\>type C:\MySQLDBA\bug_test.txt
name,\N
name,0
\N,\N
name,6
name,2
name,\N
name,0
name,0
name,\N
name,0

C:\>

Lassen Sie uns dies alles mit InnoDB wiederholen

mysql> USE test
Database changed
mysql> DROP TABLE IF EXISTS bug_repeat;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE bug_repeat
    -> (
    ->   name varchar(10),
    ->   price decimal(12,6)
    -> )
    -> ENGINE=InnoDB;
Query OK, 0 rows affected (0.05 sec)

mysql> truncate table bug_repeat;
Query OK, 0 rows affected (0.05 sec)

mysql> load data local infile 'C:/MySQLDBA/bug_test.txt'
    -> into table test.bug_repeat
    -> fields terminated by ','
    -> lines terminated by '\n';
Query OK, 10 rows affected, 4 warnings (0.00 sec)
Records: 10  Deleted: 0  Skipped: 0  Warnings: 4

mysql> show warnings\G
*************************** 1. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 1lue: 'N
*************************** 2. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 3lue: 'N
*************************** 3. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 6lue: 'N
*************************** 4. row ***************************
  Level: Warning
   Code: 1366
' for column 'price' at row 9lue: 'N
4 rows in set (0.00 sec)

mysql> select * from bug_repeat;
+------+----------+
| name | price    |
+------+----------+
| name | 0.000000 |
| name | 0.000000 |
| NULL | 0.000000 |
| name | 6.000000 |
| name | 2.000000 |
| name | 0.000000 |
| name | 0.000000 |
| name | 0.000000 |
| name | 0.000000 |
| name | 0.000000 |
+------+----------+
10 rows in set (0.00 sec)

mysql>

Welche Version von MySQL verwende ich ???

mysql> show global variables like 'version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| version                 | 5.6.22                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Win64                        |
+-------------------------+------------------------------+
4 rows in set (0.00 sec)

mysql>

Was ist mit Linux ???

$ cat /tmp/bug_test.txt
name,\N
name,0
\N,\N
name,6
name,2
name,\N
name,0
name,0
name,\N
name,0

$

Melden Sie sich bei MySQL an und versuchen Sie ...

mysql> create database test;
Query OK, 1 row affected (0.01 sec)

mysql> USE test
Database changed
mysql> DROP TABLE IF EXISTS bug_repeat;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CREATE TABLE bug_repeat
    -> (
    ->   name varchar(10),
    ->   price decimal(12,6)
    -> )
    -> ENGINE=InnoDB;
Query OK, 0 rows affected (0.09 sec)

mysql> truncate table bug_repeat;
Query OK, 0 rows affected (0.04 sec)

mysql> load data local infile 'C:/MySQLDBA/bug_test.txt'
    -> into table test.bug_repeat
    -> fields terminated by ','
    -> lines terminated by '\n';
ERROR 2 (HY000): File 'C:/MySQLDBA/bug_test.txt' not found (Errcode: 2 - No such file or directory)
mysql> show warnings\G
Empty set (0.00 sec)

mysql> select * from bug_repeat;
Empty set (0.00 sec)

mysql> truncate table bug_repeat;
Query OK, 0 rows affected (0.04 sec)

mysql> load data local infile '/tmp/bug_test.txt'
    -> into table test.bug_repeat
    -> fields terminated by ','
    -> lines terminated by '\n';
Query OK, 10 rows affected (0.00 sec)
Records: 10  Deleted: 0  Skipped: 0  Warnings: 0

mysql> show warnings\G
Empty set (0.00 sec)

mysql> select * from bug_repeat;
+------+----------+
| name | price    |
+------+----------+
| name |     NULL |
| name | 0.000000 |
| NULL |     NULL |
| name | 6.000000 |
| name | 2.000000 |
| name |     NULL |
| name | 0.000000 |
| name | 0.000000 |
| name |     NULL |
| name | 0.000000 |
+------+----------+
10 rows in set (0.00 sec)

mysql> show global variables like 'version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| version                 | 5.6.21-log                   |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
4 rows in set (0.00 sec)

mysql>

Heutiges Datum ???

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2015-06-25 18:48:10 |
+---------------------+
1 row in set (0.01 sec)

mysql>

Es ist ein Jahr und eine Woche her, seit dieser Fehlerbericht eingereicht wurde und nichts hat sich geändert.

Meine Antwort auf MySQL ist das Einfügen von "" als 0 in Dezimalfelder. Wie kann man das aufhalten? steht noch heute.

Sie müssen diesen Test gegen MySQL 5.6.23 durchführen und prüfen, ob sich etwas geändert hat.

RolandoMySQLDBA
quelle
Im Hinblick auf den LOAD DATA INFILE, ja, es ist der einzige Weg. Andernfalls werden numerische Werte, die dem IEEE-Gleitkommaformat folgen, zu 0. Da ich auf die Problemumgehung hingewiesen habe ( dba.stackexchange.com/questions/87206/… ), hat no einen IEEE-Gleitkommadatentyp erstellt, der als NULL beginnen kann.
RolandoMySQLDBA
Vielen Dank für den detaillierten reproduzierbaren Test. Die Antwort auf Ihre letzte Anweisung ist, dass sich anscheinend nichts geändert hat. Gibt es eine Begründung für dieses Verhalten? Warum wird es nicht als Fehler angesehen?
WAF
Auch nur aus Neugier, warum hat dich TRUNCATEnach CREATEin den letzten beiden Beispielen ing?
WAF
Ich habe die gleiche Tabellenstruktur beibehalten, um sie neu zu laden und erneut zu versuchen, aber mit \N. Wenn Sie sich die Problemumgehung im Fehlerbericht ansehen, gibt es einen truncate bug_repeat;Fehler beim zweiten LOAD DATA INFILEVersuch. Daher habe ich versucht, den Test der Problemumgehung zu duplizieren.
RolandoMySQLDBA