MySQL, lepiej wstawić NULL lub pusty ciąg?

230

Mam formularz na stronie internetowej, która ma wiele różnych dziedzin. Niektóre pola są opcjonalne, a niektóre są obowiązkowe. W mojej bazie danych mam tabelę zawierającą wszystkie te wartości. Czy lepiej jest wstawiać wartość NULL lub pusty ciąg do kolumn DB, w których użytkownik nie umieścił żadnych danych?

roflwaffle
źródło

Odpowiedzi:

220

Korzystając z tej opcji NULL, możesz rozróżnić pomiędzy „nie wprowadzaj danych” a „nie wprowadzaj danych”.

Kilka innych różnic:

  • A LENGTHz NULLjest NULL, a LENGTHpustego łańcucha jest 0.

  • NULLs są sortowane przed pustymi ciągami.

  • COUNT(message)policzy puste ciągi, ale nie NULLs

  • Możesz wyszukać pusty ciąg, używając zmiennej powiązanej, ale nie NULL. To zapytanie:

    SELECT  *
    FROM    mytable 
    WHERE   mytext = ?
    

    nigdy nie będzie pasować do NULLin mytext, bez względu na wartość przejechania od klienta. Aby dopasować NULLs, musisz użyć innego zapytania:

    SELECT  *
    FROM    mytable 
    WHERE   mytext IS NULL
    
Quassnoi
źródło
3
ale który według ciebie jest szybszy? 0 lub NULL lub „”
Atul Dravid
8
w InnoDB NULL zajmują mniej miejsca
Timo Huovinen,
37
Myślę, że jest to dobra odpowiedź, ale całkowicie ignoruje element „najlepszych praktyk” pytania i koncentruje się tylko na stycznie istotnych faktach (NULL sort sortable and length? To nie ma znaczenia). W przypadku większości typów wprowadzania danych tekstowych nie ma różnicy między „brakiem odpowiedzi” a „pustą odpowiedzią”, więc myślę, że to świetne pytanie, które zasługuje na lepszą odpowiedź.
Nick
6
Wartości NULL działają również świetnie, gdy ustawione jest pole UNIQUE. Na przykład, jeśli masz pole takie jak prawo jazdy, aby dodać numer DL osoby, a facet go nie ma. Ponieważ jest to unikalne pole, pierwsza osoba bez numeru DL zostanie dodana, ale nie następna, ponieważ spowoduje błąd wyjątkowego ograniczenia. Więc NULL jest lepszy.
Saifur Rahman Mohsin
1
@Quassnoi ah przepraszam ... Miałem na myśli, dlaczego złym postępowaniem jest ustawianie prawa jazdy jako unikalnego ...?
cedbeu
44

Jedną rzeczą do rozważenia, jeśli kiedykolwiek planujesz zmienić bazę danych, jest to, że Oracle nie obsługuje pustych ciągów . Są one automatycznie konwertowane na NULL i nie można ich wyszukiwać za pomocą klauzul takich jak WHERE somefield = ''.

Matt Solnit
źródło
11
Brzmiało to dla mnie niesamowicie podejrzanie, nawet na twoim linku, więc spróbowałem. Pole zerowe, ustawione na „”, wyrocznia ignoruje je. Zgłasza długość jako wartość zerową zamiast 0. To po prostu tak źle. Musi być jakiś sposób na obejście tego. Pomyśl, że opublikuję to jako kolejne pytanie.
Steve B.
1
Steve B.: patrz to pytanie: stackoverflow.com/questions/1171196/…
Quassnoi
Dzięki za referencje, choć wciąż nie rozumiem uzasadnienia. Opublikowane jako stackoverflow.com/questions/1268177/…
Steve B.
Być może warto zaktualizować odpowiedź,
dodając
7
Peoplesoft (z Oracle DB) używa pojedynczej spacji do wskazania pustej wartości. Niesamowicie głupie. Używają również 0,00025, aby wskazać 0 dla FTE, ponieważ 0 jest niedozwolone. W tym produkcie dokonano wspaniałych wyborów.
JP Duffy
9

Należy pamiętać, że NULL może znacznie utrudnić korzystanie ze ścieżek kodowych. Na przykład w Pythonie większość kart / baz danych ORM jest odwzorowanych NULLna None.

Więc takie rzeczy jak:

print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow

może spowodować „Hello, None Joe Doe!” Aby tego uniknąć, potrzebujesz czegoś takiego:

if databaserow.title:
    print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow
else:
    print "Hello, %(firstname) %(lastname)!" % databaserow

Co może sprawić, że wszystko stanie się znacznie bardziej złożone.

max
źródło
25
Moim zdaniem nadużywanie bazy danych w celu „naprawy” błędów w kodzie lub frameworku jest (bardzo) złą praktyką kodowania. Gdy nie ma danych, wystarczy wstawić NULL i konsekwentnie z nich korzystać. W przeciwnym razie musisz użyć instrukcji takich jak: if (myString == null || myString = ""). Kiedy obiekt nie jest ustawiony ani zdefiniowany w kodzie, używasz również NULL zamiast jakiegoś „symbolu zastępczego” (który moim zdaniem jest pustym łańcuchem).
Gertjan,
5
Zależy bardzo od wybranego języka. W Pythonie „jeśli nie myString:” testuje na Brak i „”. Prawdopodobnie głównie problemy kulturowe. „Zła praktyka” Java Guys to elegancja osoby dynamicznej.
maks.
9

Lepiej wstawić, aby zachować NULLspójność bazy danych w MySQL. Klucze obce mogą być przechowywane jako, NULLale NIE jako puste ciągi.

Będziesz mieć problemy z pustym ciągiem w ograniczeniach. Konieczne może być wstawienie fałszywego rekordu z unikalnym pustym ciągiem, aby spełnić ograniczenie klucza obcego. Chyba zła praktyka.

Zobacz także: Czy klucz obcy może mieć wartość NULL i / lub być duplikatem?

micaball
źródło
Kwestia ograniczeń potknęła mnie w przeszłości, dlatego „+1” dla tej odpowiedzi.
HPWD,
Ale jeśli używasz NULL, upewnij się, że nigdy nie skończysz z pustymi ciągami. Łatwe w obsłudze dzięki wielu technologiom interfejsu użytkownika.
Tuntable
5

Nie wiem, jaka byłaby najlepsza praktyka, ale ogólnie bym poparł wartość zerową, chyba że chcesz, aby wartość pusta oznaczała coś innego niż pusty ciąg, a dane wejściowe użytkownika odpowiadają definicji pustego ciągu.

Zauważ, że mówię, że musisz określić, w jaki sposób mają się różnić. Czasami sensowne jest, aby były różne, a czasem nie. Jeśli nie, wybierz jeden i trzymaj się go. Tak jak powiedziałem, mam tendencję do faworyzowania NULL przez większość czasu.

Aha, i pamiętaj, że jeśli kolumna ma wartość NULL, rekord ma mniejsze szanse na pojawienie się w praktycznie każdym zapytaniu, które wybiera (zawiera klauzulę where, w języku SQL) na podstawie tej kolumny, chyba że wybór dotyczy kolumny null oczywiście.

Platinum Azure
źródło
1
... A teraz, gdy widzę odpowiedź nade mną, myślę, że bezpiecznie jest powiedzieć, że zwykłym rozróżnieniem, na którym Ci zależy, jest brak danych w porównaniu do pustych danych. :-)
Platinum Azure,
1

Jeśli używasz wielu kolumn w unikalnym indeksie i co najmniej jedna z tych kolumn jest obowiązkowa (tj. Wymagane pole formularza), jeśli ustawisz inne kolumny w indeksie na NULL, możesz skończyć ze zduplikowanymi wierszami. Jest tak, ponieważ wartości NULL są ignorowane w unikalnych kolumnach. W takim przypadku użyj pustych ciągów w innych kolumnach unikalnego indeksu, aby uniknąć powielania wierszy.

KOLUMNY W UNIKALNYM INDEKSIE:
(typ_zdarzenia, tytuł_zdarzenia, data, lokalizacja, adres URL)

PRZYKŁAD 1:
(1, „BBQ”, „2018-07-27”, null, null)
(1, „BBQ”, „2018-07-27”, null, null) // dozwolone i powielone.

PRZYKŁAD 2:
(1, „BBQ”, „2018-07-27”, „”, „”)
(1, „BBQ”, „2018-07-27”, „”, „”) // NIE jest dozwolone, ponieważ jest duplikowane.

Oto kilka kodów:

CREATE TABLE `test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `event_id` int(11) DEFAULT NULL,
  `event_title` varchar(50) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `location` varchar(50) DEFAULT NULL,
  `url` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `event_id` (`event_id`,`event_title`,`date`,`location`,`url`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

Teraz wstaw to, aby zobaczyć, że pozwoli duplikować wiersze:

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);

Teraz wstaw to i sprawdź, czy nie jest dozwolone:

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');

Zatem nie ma tu ani dobra, ani zła. To Ty decydujesz, co najlepiej pasuje do twoich reguł biznesowych.

João Marques
źródło