Błąd w MySQL podczas ustawiania wartości domyślnej dla DATA lub DATETIME

124

Używam MySql Server 5.7.11 i to zdanie:

updated datetime NOT NULL DEFAULT '0000-00-00 00:00:00'

to nie działa. Podając błąd:

ERROR 1067 (42000): Invalid default value for 'updated'

Ale następujące:

updated datetime NOT NULL DEFAULT '1000-01-01 00:00:00'

po prostu działa .

To samo dotyczy DATE.

Na marginesie wspomniano o tym w dokumentacji MySQL :

Typ DATA jest używany dla wartości z częścią daty, ale bez części czasu. MySQL pobiera i wyświetla wartości DATE w formacie „RRRR-MM-DD”. Obsługiwany zakres to od „1000-01-01” do „9999-12-31”.

nawet jeśli mówią również:

Nieprawidłowe wartości DATE, DATETIME lub TIMESTAMP są konwertowane na wartość „zero” odpowiedniego typu („0000-00-00” lub „0000-00-00 00:00:00”).

Biorąc również pod uwagę drugi cytat z dokumentacji MySQL, czy ktoś mógłby mi powiedzieć, dlaczego podaje ten błąd?

Evhz
źródło
11
Dlaczego miałbyś chcieć wartości domyślnej, która jest oczywiście bez znaczenia? Jeśli data nie jest znana, to właśnie po to NULL.
Tom H
Uwaga: to działa w wersji 5.6 na SQL Fiddle - sqlfiddle.com/#!9/02c98 .
Gordon Linoff
@Karlos sprawdź zaktualizowaną odpowiedź.
geeksal

Odpowiedzi:

209

Błąd jest spowodowany trybem sql, który może być trybem ścisłym, zgodnie z najnowszą dokumentacją MYSQL 5.7

Dokumentacja MySQL 5.7 mówi :

Tryb ścisły wpływa na to, czy serwer zezwala na „0000-00-00” jako prawidłową datę: Jeśli tryb ścisły nie jest włączony, dozwolony jest tryb „0000-00-00”, a wstawienia nie generują ostrzeżenia. Jeśli włączony jest tryb ścisły, „0000-00-00” jest niedozwolone, a wstawienia powodują błąd, chyba że podano również IGNORE. W przypadku INSERT IGNORE i UPDATE IGNORE dozwolone jest ustawienie „0000-00-00”, a wstawianie powoduje wyświetlenie ostrzeżenia.

Aby sprawdzić tryb MYSQL

SELECT @@GLOBAL.sql_mode global, @@SESSION.sql_mode session

Wyłączanie trybu STRICT_TRANS_TABLES

Jednak aby zezwolić na format 0000-00-00 00:00:00, musisz wyłączyć tryb STRICT_TRANS_TABLES w pliku konfiguracyjnym mysql lub poleceniem

Na rozkaz

SET sql_mode = '';

lub

SET GLOBAL sql_mode = '';

Użycie słowa kluczowego GLOBALwymaga super previliges i ma wpływ na operacje, które od tego momentu łączą się wszyscy klienci

jeśli powyższe nie działa, przejdź do /etc/mysql/my.cnf(zgodnie z ubuntu) i skomentujSTRICT_TRANS_TABLES

Ponadto, jeśli chcesz na stałe ustawić tryb sql podczas uruchamiania serwera, dołącz go SET sql_mode=''w my.cnfsystemie Linux lub MacOS. W przypadku systemu Windows należy to zrobić w my.inipliku.

Uwaga

Jednak tryb ścisły nie jest domyślnie włączony w MYSQL 5.6. W związku z tym nie powoduje błędu zgodnie z dokumentacją MYSQL 6, która mówi

MySQL umożliwia przechowywanie „zerowej” wartości „0000-00-00” jako „fikcyjnej daty”. W niektórych przypadkach jest to wygodniejsze niż używanie wartości NULL i zużywa mniej miejsca na dane i indeks. Aby zabronić „0000-00-00”, włącz tryb SQL NO_ZERO_DATE.

AKTUALIZACJA

Odnośnie sprawy błędu, jak powiedział @ Dylan-Su:

Nie wydaje mi się, żeby to był błąd, który wynika ze sposobu, w jaki MYSQL ewoluował w czasie, przez co pewne rzeczy ulegają zmianie w oparciu o dalsze ulepszanie produktu.

Jednak mam inny powiązany raport o błędzie dotyczący tej NOW()funkcji

Pole daty i godziny nie akceptuje domyślnej TERAZ ()

Kolejna przydatna uwaga [patrz Automatyczna inicjalizacja i aktualizacja dla TIMESTAMP i DATETIME ]

Począwszy od MySQL 5.6.5, kolumny TIMESTAMP i DATETIME mogą być automatycznie inicjowane i aktualizowane zgodnie z aktualną datą i godziną (czyli aktualną sygnaturą czasową). Przed wersją 5.6.5 było to prawdziwe tylko dla TIMESTAMP i co najwyżej dla jednej kolumny TIMESTAMP na tabelę. Poniższe uwagi opisują najpierw automatyczną inicjalizację i aktualizację MySQL 5.6.5 i nowszych, a następnie różnice w wersjach wcześniejszych niż 5.6.5.

Aktualizacja dotycząca NO_ZERO_DATE

Od wersji MySQL 5.7.4 ten tryb jest przestarzały. W poprzedniej wersji musisz zakomentować odpowiednią linię w pliku konfiguracyjnym. Zapoznaj się z dokumentacją MySQL 5.7 w dniu NO_ZERO_DATE

geeksal
źródło
5
UPDATE IGNORE jest tym, czego szukałem 👍🏻
Afanasii Kurakin
2
Źle. Mam STRICT_TRANS_TABLESdla moich obu instancji MySQL, lokalnego i serwera. Jednak mogę łatwo wstawić 0000-00-00w mojej instancji lokalnej, ale nie mogę w mojej instancji serwera - generowany jest błąd. Czemu? Ponieważ konfiguracja MySQL mojego serwera jest NO_ZERO_DATEwłączona. A mój lokalny tego nie ma.
Green
ok @Green Wymyślę i zaktualizuję odpowiedź, jeśli dotyczy
geeksal
4
W moim przypadku 'SET sql_mode = ""' nie działało. 'SET GLOBAL sql_mode = "";' wykonał pracę za mnie.
arjen Stens
Również NO_ZERO_DATEpowinny zostać usunięte
Preshan Pradeepa
18

Miałem ten błąd z WAMP 3.0.6 z MySql 5.7.14.

Rozwiązanie :

zmień linię 70 (jeśli twój plik ini jest nietknięty) w c:\wamp\bin\mysql\mysql5.7.14\my.inipliku z

sql-mode= "STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ZERO_DATE,NO_ZERO_IN_DATE,NO_AUTO_CREATE_USER"

do

sql-mode="ERROR_FOR_DIVISION_BY_ZERO,NO_ZERO_DATE,NO_ZERO_IN_DATE,NO_AUTO_CREATE_USER"

i uruchom ponownie wszystkie usługi.

Spowoduje to wyłączenie trybu ścisłego. Zgodnie z dokumentacją „tryb ścisły” oznacza tryb z jednym lub obydwoma STRICT_TRANS_TABLESlub STRICT_ALL_TABLESwłączonymi. Dokumentacja mówi:

„Domyślny tryb SQL w MySQL 5.7 obejmuje następujące tryby: ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_TABLES i NO_ENGINE_SUBSTUTION”.

bg17aw
źródło
14

Doszedłem do sytuacji, w której dane zostały zmieszane między NULL i 0000-00-00 dla pola daty. Ale nie wiedziałem, jak zaktualizować '0000-00-00' do NULL, ponieważ

 update my_table set my_date_field=NULL where my_date_field='0000-00-00'

nie jest już dozwolone. Moje obejście było dość proste:

update my_table set my_date_field=NULL where my_date_field<'1000-01-01'

ponieważ wszystkie niepoprawne my_date_fieldwartości (bez względu na to, czy są prawidłowe, czy nie) pochodzą sprzed tej daty.

Martin T.
źródło
2
Idealne szybkie rozwiązanie. W rzeczywistości możesz również użyć, <'0000-01-01'ponieważ jest to oczywiście ważna data.
Ricky McMaster
5

Problem ze składnią konfiguracji

W niektórych wersjach MYSQL (testowane 5.7. *) W systemach * nix powinieneś użyć następującej składni:

[mysqld]

sql-mode="NO_BACKSLASH_ESCAPES,STRICT_TRANS_TABLE,NO_ENGINE_SUBSTITUTION"

Te nie będą działać:

kreska bez cytatów

sql-mode=NO_ENGINE_SUBSTITUTION

podkreślenie bez cudzysłowów

sql_mode=NO_ENGINE_SUBSTITUTION

podkreślenie i cytaty

sql_mode="NO_ENGINE_SUBSTITUTION"

Bardziej szczegółowy przegląd wartości konfiguracyjnych i trybu sql:

Jak skonfigurować stałe flagi trybu Sql

Heroselohim
źródło
5

Najpierw wybierz bieżącą sesję sql_mode:

SELECT @@SESSION.sql_mode;

Wtedy otrzymasz coś takiego jak ta domyślna wartość :

„ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION”

a następnie ustaw sql_modebez 'NO_ZERO_DATE':

SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

Jeśli masz stypendia, możesz to zrobić również dla GLOBAL:

SELECT @@GLOBAL.sql_mode;
SET GLOBAL sql_mode = '...';
simhumileco
źródło
4

Po prostu dodaj linię: sql_mode = "NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

plik wewnętrzny: /etc/mysql/mysql.conf.d/mysqld.cnf

następnie sudo service mysql restart

ferreidon aftahi
źródło
1
Działa na 5.7.23.
user2513149
1
Prawdopodobnie zasugerowałbym SELECT @@SESSION.sql_mode;najpierw, a oni usuną NO_ZERO_IN_DATE, NO_ZERO_DATE i STRICT_TRANS_TABLES z tego, co ci daje. W ten sposób zachowasz wszystkie inne włączone ustawienia. Miałem dużo więcej niż tylko te dwa elementy ustawione dla mojego trybu sql. Nie wiem, co wszyscy robią, ale nie chcę ryzykować usunięcia ich w tym momencie.
Radley Sustaire
2

Działa dla 5.7.8:

mysql> create table t1(updated datetime NOT NULL DEFAULT '0000-00-00 00:00:00');
Query OK, 0 rows affected (0.01 sec)

mysql> show create table t1;
+-------+-------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                            |
+-------+-------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
+-------+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.8-rc  |
+-----------+
1 row in set (0.00 sec)

Możesz utworzyć SQLFiddle, aby odtworzyć problem.

http://sqlfiddle.com/

Jeśli działa z MySQL 5.6 i 5.7.8, ale nie działa w wersji 5.7.11. Zatem prawdopodobnie będzie to błąd regresji w wersji 5.7.11.

Dylan Su
źródło
1

Aby rozwiązać problem z MySQL Workbench (po zastosowaniu rozwiązania po stronie serwera):

Usuń SQL_MODE do TRADITIONAL w panelu preferencji.

wprowadź opis obrazu tutaj

Vindic
źródło
1

Ta odpowiedź dotyczy tylko MySQL 5.7:

Najlepsza nie jest tak naprawdę ustawiona w pustym trybie sql_mode, zamiast tego użyj w PHP zmiennej sesji z:

SET SESSION sql_mode= 'ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

Więc przynajmniej zachowujesz inne wartości domyślne.

To szalone, że dokumentacja mysql nie jest jasna, musisz usunąć te domyślne wartości w sql_mode:

NO_ZERO_IN_DATE, NO_ZERO_DATE, rozumiem, ale w przyszłych wersjach zostanie to wycofane.

STRICT_ALL_TABLES, z tym, zanim parametry zostaną zignorowane, więc musisz je również usunąć.

Wreszcie również TRADYCYJNE, ale dokumentacja mówi o tym parametrze: „podawaj błąd zamiast ostrzeżenia” przy wstawianiu nieprawidłowej wartości do kolumny ”, z tym parametrem nie wstawia się dat o zerowej wartości, ale bez tak.

MySQL nie jest tak naprawdę zorganizowany z tymi parametrami i kombinacjami.

stackdave
źródło
0

Kombinacje opcji dla mysql Ver 14.14 Distrib 5.7.18, for Linux (x86_64).

Nie rzuca:

STRICT_TRANS_TABLES + NO_ZERO_DATE

Rzuty:

STRICT_TRANS_TABLES + NO_ZERO_IN_DATE

Moje ustawienia w /etc/mysql/my.cnfUbuntu:

[mysqld]
sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
Zielony
źródło
0
set global sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
Aris tri jaka
źródło
0

W katalogu xamp / mysql / bin Otwórz "my.ini" i zmień wiersz: Sql_node for ->

„sql_mode = NO_ENGINE_SUBSTITUTION, NO_ZERO_DATE”

USUŃ „NO_ZERO_IN_DATE”

leandro ramos
źródło
Witamy w stackoverflow, użyj odpowiedniego formatowania kodu, aby poprawić czytelność odpowiedzi.
vlizana