2014-09-24 19 views
6

Đối với một chút nền, chúng tôi sử dụng Zend Framework 2Doctrine tại nơi làm việc. Giáo lý sẽ luôn chèn NULL cho các giá trị mà chúng tôi không cư trú. Thông thường, điều này là không sao nếu trường có giá trị mặc định, sau đó NÊN điền trường bằng giá trị mặc định này.Chèn NULL vào cột NOT NULL với Giá trị Mặc định

Đối với một trong các máy chủ của chúng tôi chạy MySQL 5.6.16 truy vấn như truy vấn bên dưới chạy và thực thi tốt. Mặc dù NULL đang được chèn vào một trường không có giá trị rỗng, nhưng MySQL sẽ điền vào trường với giá trị mặc định của nó khi chèn.

Trên một máy chủ khác đang chạy MySQL 5.6.20, chúng tôi chạy truy vấn bên dưới và nó kết thúc vì nó phàn nàn 'field_with_default_value' KHÔNG THỂ rỗng.

INSERT INTO table_name(id, field, field_with_default_value) 
VALUES(id_value, field_value, NULL); 

Bản thân giáo lý không hỗ trợ chuyển qua "DEFAULT" vào truy vấn được xây dựng để không phải là tùy chọn. Tôi hình dung điều này phải là một máy chủ MySQL của một số loại nhìn thấy như thể nó hoạt động ổn trong một phiên bản nhưng không phải là một phiên bản khác, nhưng tiếc là tôi không có ý tưởng điều này có thể được. Chế độ SQL của chúng tôi cũng giống nhau trên cả hai máy chủ ('NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION').

Tôi có lẽ nên đề cập đến, nếu tôi thực sự chạy SQL ở trên trong Bàn làm việc, nó vẫn không hoạt động theo cùng một cách. Vì vậy, nó không thực sự là một vấn đề của Doctrine nhưng chắc chắn là một vấn đề về MySQL.

Bất kỳ trợ giúp nào về điều này sẽ được đánh giá cao.

+0

Bạn có chắc chắn rằng chế độ SQL giống hệt nhau không? xem https://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html – MrTux

+0

Đúng, tôi thậm chí đã sao chép qua Chế độ SQL từ một máy chủ này sang máy chủ khác để kiểm tra kỹ xem chúng có giống nhau hay không. –

+0

Bạn có STRICT_TRANS_TABLES chế độ sql, vì vậy nếu bạn chạy cả hai truy vấn om dòng lệnh, bạn sẽ có tác dụng tương tự. Có lẽ Doctrine thay đổi điều này? (Một lý do khác không sử dụng Doctrine) – Gervs

Trả lời

1

Theo tài liệu, mọi thứ hoạt động như mong đợi.

Kiểm tra trường hợp:

mysql> use test; 
Reading table information for completion of table and column names 
You can turn off this feature to get a quicker startup with -A 

Database changed 
mysql> SELECT VERSION(); 
+-----------+ 
| VERSION() | 
+-----------+ 
| 5.6.16 | 
+-----------+ 
1 row in set (0.00 sec) 

mysql> SELECT @@GLOBAL.sql_mode 'sql_mode::GLOBAL', 
       @@SESSION.sql_mode 'sql_mode::SESSION'; 
+------------------------+------------------------+ 
| sql_mode::GLOBAL  | sql_mode::SESSION  | 
+------------------------+------------------------+ 
| NO_ENGINE_SUBSTITUTION | NO_ENGINE_SUBSTITUTION | 
+------------------------+------------------------+ 
1 row in set (0.00 sec) 

mysql> SET SESSION sql_mode := 'NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; 
Query OK, 0 rows affected (0.00 sec) 

mysql> SELECT @@GLOBAL.sql_mode 'sql_mode::GLOBAL', 
       @@SESSION.sql_mode 'sql_mode::SESSION'; 
+------------------------+-----------------------------------------------------------------------------------------------------------------+ 
| sql_mode::GLOBAL  | sql_mode::SESSION                        | 
+------------------------+-----------------------------------------------------------------------------------------------------------------+ 
| NO_ENGINE_SUBSTITUTION | NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION | 
+------------------------+-----------------------------------------------------------------------------------------------------------------+ 
1 row in set (0.00 sec) 

mysql> SHOW CREATE TABLE `table_name`; 
+------------+----------------------------------------------------------------------------+ 
| Table  | Create Table                | 
+------------+----------------------------------------------------------------------------+ 
| table_name | CREATE TABLE `table_name` (            | 
|   |  `id` INT(11) UNSIGNED NOT NULL,          | 
|   |  `field` VARCHAR(20) DEFAULT NULL,         | 
|   |  `field_with_default_value` VARCHAR(20) NOT NULL DEFAULT 'myDefault' | 
|   |) ENGINE=InnoDB DEFAULT CHARSET=latin1          | 
+------------+----------------------------------------------------------------------------+ 
1 row in set (0.00 sec) 

mysql> INSERT INTO `table_name`(`id`, `field`, `field_with_default_value`) 
     VALUES 
     (1, 'Value', NULL); 
ERROR 1048 (23000): Column 'field_with_default_value' cannot be null 

Có thể đăng các phần có liên quan về cấu trúc của bảng của bạn để xem làm thế nào chúng ta có thể giúp đỡ?

CẬP NHẬT

MySQL 5.7, sử dụng gây nên, có thể cung cấp một giải pháp khả thi cho vấn đề:

Changes in MySQL 5.7.1 (2013-04-23, Milestone 11)

...

  • Nếu một cột được khai báo là NOT NULL , không được phép chèn NULL vào cột hoặc cập nhật nó thành NULL. Tuy nhiên, ràng buộc này đã được thực thi ngay cả khi có BEFORE INSERT (hoặc BEFORE UPDATE kích hoạt) để đặt cột thành giá trị không NULL. Bây giờ ràng buộc được chọn ở cuối câu lệnh, theo tiêu chuẩn SQL. (Bug #6295, Bug # 11744964).

...

giải pháp có thể:

mysql> use test; 
Reading table information for completion of table and column names 
You can turn off this feature to get a quicker startup with -A 

Database changed 
mysql> SELECT VERSION(); 
+-----------+ 
| VERSION() | 
+-----------+ 
| 5.7.4-m14 | 
+-----------+ 
1 row in set (0.00 sec) 

mysql> DELIMITER $$ 

mysql> CREATE TRIGGER `trg_bi_set_default_value` BEFORE INSERT ON `table_name` 
     FOR EACH ROW 
     BEGIN 
      IF (NEW.`field_with_default_value` IS NULL) THEN 
      SET NEW.`field_with_default_value` := 
       (SELECT `COLUMN_DEFAULT` 
       FROM `information_schema`.`COLUMNS` 
       WHERE `TABLE_SCHEMA` = DATABASE() AND 
         `TABLE_NAME` = 'table_name' AND 
         `COLUMN_NAME` = 'field_with_default_value'); 
      END IF; 
     END$$ 

mysql> DELIMITER ; 

mysql> INSERT INTO `table_name`(`id`, `field`, `field_with_default_value`) 
     VALUES 
     (1, 'Value', NULL); 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT `id`, `field`, `field_with_default_value` FROM `table_name`; 
+----+-------+--------------------------+ 
| id | field | field_with_default_value | 
+----+-------+--------------------------+ 
| 1 | Value | myDefault    | 
+----+-------+--------------------------+ 
1 row in set (0.00 sec) 
+0

Xem câu trả lời của tôi.Tôi nghĩ nó giải thích tình hình. –

0

MySQL thực sự hoạt động như dự định, and that behavior seems to be there to stay. MariaDB also works the same way now.

Loại bỏ "strict mode" (STRICT_TRANS_TABLES & STRICT_ALL_TABLES) có nghĩa vụ phải trở lại các hành vi trước, nhưng cá nhân tôi không có bất kỳ may mắn với nó (có lẽ tôi đang làm điều gì sai, nhưng cả hai tôi @@GLOBAL.sql_mode & @@SESSION.sql_mode không chứa nghiêm ngặt chế độ).

Tôi nghĩ giải pháp tốt nhất cho vấn đề này là dựa vào các giá trị mặc định ở cấp PHP, thay vì dựa vào Cơ sở dữ liệu để cung cấp chúng. There is an existing answer that explains it pretty well. Nhận xét cũng hữu ích.

Bằng cách đó, bạn cũng nhận được lợi ích bổ sung mà các mô hình/thực thể của bạn sẽ có giá trị mặc định khi khởi tạo thay vì khi chèn vào cơ sở dữ liệu. Ngoài ra, nếu bạn muốn hiển thị các giá trị đó cho người dùng sau khi chèn, bạn có thể làm như vậy mà không phải thực hiện thêm truy vấn SELECT sau INSERT.

Một giải pháp thay thế cho bề mặt các giá trị mặc định là sử dụng RETURNING clause, như có sẵn trong PostgreSQL, nhưng không có trong MySQL (chưa). Nó có thể được thêm vào tại một thời điểm nào đó trong tương lai, nhưng bây giờ là MariaDB only has it for DELETE statements. Tuy nhiên, tôi tin rằng việc có các giá trị mặc định ở cấp PHP vẫn cao hơn; ngay cả khi bạn không bao giờ chèn bản ghi, nó vẫn sẽ chứa các giá trị mặc định. Tôi chưa bao giờ quay lại và sử dụng một giá trị mặc định của cơ sở dữ liệu từ khi đưa nó vào thực tế.

0

Dựa trên nghiên cứu của tôi, tôi sẽ nói rằng cả hai có thể là một điều "bạn" và một điều "MySQL". Kiểm tra các định nghĩa bảng của bạn với SHOW CREATE TABLE table_name;. Lưu ý bất kỳ trường nào được xác định với NOT NULL.

Các MySQL 5.6 Reference Manual: 13.2.5 INSERT syntax trạng thái:

Chèn NULL vào cột đó đã được tuyên bố NOT NULL. Đối với câu lệnh INSERT nhiều hàng hoặc INSERT INTO ... câu lệnh SELECT, cột được đặt thành ẩn giá trị mặc định cho dữ liệu cột loại. Đây là 0 cho kiểu số, chuỗi rỗng ('') cho chuỗi loại và giá trị “không” cho các loại ngày và giờ. INSERT INTO ... Câu lệnh SELECT được xử lý giống như cách chèn nhiều hàng vì máy chủ không kiểm tra tập hợp kết quả từ SELECT đến xem liệu nó có trả về một hàng hay không. (Đối với một INSERT đơn hàng, không cảnh báo xảy ra khi NULL được đưa vào một cột NOT NULL. Thay vào đó, báo cáo kết quả không thành công với một lỗi.)

Điều này có nghĩa rằng nó không quan trọng mà Chế độ SQL bạn đang sử dụng. Nếu bạn đang thực hiện một hàng đơn lẻ INSERT (theo mã mẫu của bạn) và chèn một giá trị NULL vào một cột được xác định với NOT NULL, nó không phải là hoạt động.

Trong cùng một hơi thở, trớ trêu thay, nếu bạn đã chỉ đơn giản là bỏ qua các giá trị từ danh sách giá trị, hướng dẫn MySQL nói sau đây, và chế độ SQL không thành vấn đề trong trường hợp này:

Nếu bạn không chạy trong chế độ SQL nghiêm ngặt, bất kỳ cột nào không rõ ràng được đưa ra một giá trị được thiết lập mặc định của nó (rõ ràng hoặc ngầm) giá trị. Ví dụ: , nếu bạn chỉ định danh sách cột không đặt tên tất cả các cột trong bảng, cột chưa đặt tên được đặt thành giá trị mặc định của chúng. Phân bổ giá trị mặc định được mô tả trong Phần 11.6, “Kiểu dữ liệu Giá trị mặc định”. Xem thêm Phần 1.7.3.3, “Các ràng buộc trên Dữ liệu không hợp lệ”.

Vì vậy, bạn không thể thắng! ;-) Đùa. Điều cần làm là chấp nhận rằng NOT NULL trên một trường bảng MySQL thực sự có nghĩa là Tôi sẽ không chấp nhận giá trị NULL cho một trường trong khi thực hiện một hàng đơn INSERT, bất kể chế độ SQL. '

Tất cả những gì đang được nói, sau đây từ sổ tay cũng đúng:

Đối với nhập dữ liệu vào một cột NOT NULL mà không có rõ ràng khoản DEFAULT , nếu một INSERT hoặc REPLACE tuyên bố bao gồm không có giá trị cho các cột, hoặc một câu lệnh UPDATE đặt cột để NULL, MySQL xử lý cột theo chế độ SQL có hiệu lực vào thời điểm đó:

Nếu nghiêm ngặt chế độ SQL được kích hoạt, một Lỗi n xảy ra cho các bảng giao dịch và câu lệnh được cuộn lại. Đối với các bảng không biên dịch, xảy ra lỗi, nhưng nếu điều này xảy ra cho hàng thứ hai hoặc tiếp theo của câu lệnh nhiều hàng, các hàng trước sẽ là được chèn.

Nếu chế độ nghiêm ngặt không được bật, MySQL đặt cột thành ẩn ngụ giá trị mặc định cho loại dữ liệu cột.

Vì vậy, hãy tận tâm. Đặt các giá trị mặc định của bạn trong logic nghiệp vụ (các đối tượng) và để cho lớp dữ liệu lấy hướng từ đó. Mặc định cơ sở dữ liệu có vẻ như là một ý tưởng hay, nhưng nếu chúng không tồn tại, bạn có nhớ chúng không? Nếu một cây rơi trong rừng ...

Các vấn đề liên quan