MySQL memuat NULL dalam kolom angka

8

MySQL 5.6.23, InnoDB

Saya memuat tabel dari file teks dibatasi karakter menggunakan LOAD DATA INFILEcommnd dan saya ingin setiap bidang dengan a \N, yang merupakan NULLkarakter dalam pengaturan ini, untuk menempatkan a NULLdi dalam tabel. Beberapa tipe numerik memiliki perilaku ini, sedangkan yang lain menempatkan a 0. Saya menggunakan FIELDS TERMINATED BYdan beberapa kolom mendapatkan NULLnilai dengan benar , jadi ini bukan masalah format baris tetap.

Ini adalah tipe yang saya amati saat menguji:

  • INTsisipan NULLs
  • DECIMAL(x,0)sisipan NULLs
  • DECIMAL(x,y)sisipan 0.0s
  • FLOATsisipan 0s
  • DOUBLE(x,y)sisipan 0.0s
  • DOUBLEsisipan 0s

Semua kolom yang dimaksud didefinisikan dengan DEFAULT NULL. Saya tahu bahwa berbagai fungsi dapat mengubah ini 0menjadi NULLs. Pertanyaannya adalah apakah ada tipe data yang dapat menangani presisi desimal dan juga akan memasukkan NULLs pada beban.

Selain itu, saya melihat sejumlah pertanyaan terkait dengan kesalahpahaman tentang perbedaan antara string, string kosong, dan nilai nol. ( contoh contoh contoh ) Ini bukan masalah, karena ada NULLdi sana dan dimuat dengan benar ke dalam kolom yang sama ketika saya mendefinisikan kembali sebagai DECIMAL (x, 0), kemudian tidak tepat ketika didefinisikan sebagai DECIMAL (x, 3).

WAF
sumber

Jawaban:

5

Jawaban yang sangat singkat: Tidak ada tipe data baru yang dibuat untuk mengakomodasi Anda.

Sementara kita membahas hal ini

Mari kita coba SQL biasa

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;

Apakah ini berhasil ???

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>

Baiklah. Ini bekerja dengan SQL. Anda bertanya tentangLOAD DATA INFILE

Anda membuka pos yang saya jawab: MySQL sedang memasukkan "" sebagai 0 dalam bidang desimal. Bagaimana cara menghentikannya?

Mari kita lihat apakah bug itu telah diatasi sejak dikirimkan. Saya akan mencoba menduplikasi kode dalam bug yang tidak berfungsi.

Pertama mari kita buat tabel itu dari laporan bug

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>

Selanjutnya, mari kita buat beberapa data

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

C:\>

Mari kita jalankan LOAD DATA INFILE

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

Aduh, apa yang terjadi

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>

Apa sql_mode?

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

mysql>

Mari kita kosongkan sql_mode, pangkas tabel dan muat ulang

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>

Biarkan dokter memasukkan file input dengan \Nseperti laporan bug

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:\>

Mari kita ulangi semua ini dengan InnoDB

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>

MySQL versi apa yang saya gunakan ???

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>

Bagaimana dengan 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

$

Masuk ke mysql dan mencoba ...

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>

Tanggal hari ini ???

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

mysql>

Sudah satu tahun dan satu minggu sejak laporan bug itu disampaikan dan tidak ada yang berubah.

Jawaban saya untuk MySQL adalah memasukkan "" sebagai 0 dalam bidang desimal. Bagaimana cara menghentikannya? masih berdiri sampai hari ini.

Anda perlu melakukan tes ini terhadap MySQL 5.6.23 dan melihat apakah ada sesuatu yang berubah.

RolandoMySQLDBA
sumber
Berkenaan dengan LOAD DATA INFILE, ya, itu satu-satunya cara. Jika tidak, nilai numerik yang mengikuti format titik mengambang IEEE menjadi 0. Karena saya menunjukkan solusi ( dba.stackexchange.com/questions/87206/… ), tidak ada yang membuat datatype titik mengambang IEEE yang dapat dimulai sebagai NULL.
RolandoMySQLDBA
Terima kasih untuk tes yang direproduksi secara terperinci. Jawaban untuk instruksi terakhir Anda adalah ternyata tidak ada yang berubah. Apakah ada alasan untuk perilaku ini? Mengapa itu tidak dianggap sebagai bug?
WAF
Juga, hanya karena penasaran, mengapa Anda TRUNCATEmengikuti CREATEdua contoh terakhir?
WAF
Saya menjaga struktur tabel yang sama untuk memuat ulang dan mencoba lagi tetapi dengan \N. Jika Anda melihat solusinya dalam laporan bug, ada upaya truncate bug_repeat;kedua LOAD DATA INFILE. Jadi, saya mencoba menduplikasi tes solusinya.
RolandoMySQLDBA