Zapisać tablicę PHP w MySQL?

88

Jaki jest dobry sposób na zapisanie tablicy danych w jednym polu mysql?

Również po zapytaniu o tę tablicę w tabeli mysql, jaki jest dobry sposób na przywrócenie jej z powrotem do postaci tablicowej?

Czy serializacja i nieserializacja są odpowiedzią?

JasonDavis
źródło

Odpowiedzi:

87

Nie ma dobrego sposobu na przechowywanie tablicy w jednym polu.

Musisz zbadać swoje dane relacyjne i wprowadzić odpowiednie zmiany w swoim schemacie. Zobacz przykład poniżej, aby zapoznać się z tym podejściem.

Jeśli trzeba zapisać tablicę do jednego pola wtedy serialize()i unserialize()funkcje rade. Ale nie możesz wykonywać zapytań dotyczących rzeczywistej zawartości.

Alternatywą dla funkcji serializacji jest również json_encode()i json_decode().

Rozważmy następującą tablicę

$a = array(
    1 => array(
        'a' => 1,
        'b' => 2,
        'c' => 3
    ),
    2 => array(
        'a' => 1,
        'b' => 2,
        'c' => 3
    ),
);

Aby zapisać go w bazie danych, musisz utworzyć taką tabelę

$c = mysql_connect($server, $username, $password);
mysql_select_db('test');
$r = mysql_query(
    'DROP TABLE IF EXISTS test');
$r = mysql_query(
    'CREATE TABLE test (
      id INTEGER UNSIGNED NOT NULL,
      a INTEGER UNSIGNED NOT NULL,
      b INTEGER UNSIGNED NOT NULL,
      c INTEGER UNSIGNED NOT NULL,
      PRIMARY KEY (id)
    )');

Aby pracować z rekordami, możesz wykonywać takie zapytania (i tak, to jest przykład, uważaj!)

function getTest() {
    $ret = array();
    $c = connect();
    $query = 'SELECT * FROM test';
    $r = mysql_query($query,$c);
    while ($o = mysql_fetch_array($r,MYSQL_ASSOC)) {
        $ret[array_shift($o)] = $o;
    }
    mysql_close($c);
    return $ret;
}
function putTest($t) {
    $c = connect();
    foreach ($t as $k => $v) {
        $query = "INSERT INTO test (id,".
                implode(',',array_keys($v)).
                ") VALUES ($k,".
                implode(',',$v).
            ")";
        $r = mysql_query($query,$c);
    }
    mysql_close($c);
}

putTest($a);
$b = getTest();

connect()Zwraca zasób połączenia mysql

function connect() {
    $c = mysql_connect($server, $username, $password);
    mysql_select_db('test');
    return $c;
}
Peter Lindqvist
źródło
26

Ogólnie rzecz biorąc, tak, serializacja i nieserializacja są drogą do zrobienia.

Jeśli jednak twoje dane są czymś prostym, zapisanie jako ciąg rozdzielany przecinkami prawdopodobnie byłoby lepsze dla przestrzeni dyskowej. Jeśli wiesz, że twoja tablica będzie na przykład tylko listą liczb, powinieneś użyć implode / explode. To różnica między 1,2,3a a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}.

Jeśli nie, to serializuj i nieserializuj pracę dla wszystkich przypadków.

Matchu
źródło
23
Skoro tu jesteś, czytelniku, zamierzam poświęcić trochę czasu na ogłoszenie, że odkąd przez lata doświadczeń odkryłem, że tak naprawdę nie jest to właściwe. Przyjęta odpowiedź to znacznie silniejsze podejście.
Matchu
4
Sine tu jesteś, czytelniku, podzielę się z Tobą, że to po prostu zależy od Twoich wymagań. Jeśli nie potrzebujesz zapytać o wartości swojej tablicy i potrzebujesz czegoś, co jest bardzo SZYBKIE, możesz bezpiecznie przechowywać swoje dane w jednym polu (co jest wyraźnie określone w pytaniu), uderz w niego kluczem głównym i gotowe . Jeśli zastanawiasz się, czym jest aplikacja: wysyłanie danych do kolejki, która jest pobierana przez cron co 5 minut. Inny cron tworzy tablice, co zajmuje znacznie więcej czasu. Kolejka pobiera obliczone dane i przekazuje je do interfejsu API innej firmy. Nie ma lepszego sposobu na zrobienie tego.
Rid Iculous
1
@RidIculous Jestem zdezorientowany, czy mówisz o swoim osobistym wniosku, czy o aplikacji, która doprowadziła do zadania pytania?
Peter Lindqvist,
1
Chociaż nie ma to znaczenia dla przesłanki mojego stwierdzenia, przedrostek „Jeśli zastanawiasz się, co to za wniosek”, powinien zapewnić jasność.
Rid Iculous
10

Po prostu użyj funkcji serializacji PHP:

<?php
$myArray = array('1', '2');
$seralizedArray = serialize($myArray);
?>

Jeśli jednak używasz takich prostych tablic, równie dobrze możesz użyć implodowania i eksplodowania. Użyj pustej tablicy zamiast nowej.

KramerC
źródło
9

Macierz Serialize / Unserialize do przechowywania w bazie danych

Odwiedź http://php.net/manual/en/function.serialize.php

Z podręcznika PHP:

Zajrzyj do sekcji „Powrót” na stronie

Zwraca ciąg znaków zawierający reprezentację wartości w strumieniu bajtów, która może być przechowywana w dowolnym miejscu.

Zauważ, że jest to ciąg binarny, który może zawierać bajty zerowe i musi być przechowywany i traktowany jako taki. Na przykład dane wyjściowe serialize () powinny zasadniczo być przechowywane w polu BLOB w bazie danych, a nie w polu CHAR lub TEXT.

Uwaga: jeśli chcesz przechowywać kod HTML w obiekcie blob, pamiętaj o zakodowaniu go w standardzie Base64, w przeciwnym razie może to spowodować uszkodzenie funkcji serializacji.

Przykładowe kodowanie:

$YourSerializedData = base64_encode(serialize($theHTML));

$YourSerializedData jest teraz gotowy do przechowywania w obiekcie blob.

Po pobraniu danych z bloba należy wykonać base64_decode, a następnie odserializować Przykładowe dekodowanie:

$theHTML = unserialize(base64_decode($YourSerializedData));
seaBass
źródło
8

Najlepszym sposobem, jaki znalazłem dla siebie, jest zapisanie tablicy jako ciągu danych ze znakami separatora

$array = array("value1", "value2", "value3", "...", "valuen");
$array_data = implode("array_separator", $array);

$query = "INSERT INTO my_tbl_name (id, array_data) VALUES(NULL,'" . $array_data . "');";

Następnie możesz przeszukiwać dane przechowywane w tablicy za pomocą prostego zapytania

$query = "SELECT * FROM my_tbl_name WHERE array_data LIKE '%value3%'";

użyj funkcji explode (), aby przekonwertować ciąg „array_data” na tablicę

$array = explode("array_separator", $array_data);

zwróć uwagę, że to nie działa z tablicami wielowymiarowymi i upewnij się, że twój "separator_tablic" jest unikalny i nie istnieje w wartościach tablicowych.

Bądź ostrożny !!! jeśli po prostu weźmiesz dane formularza i umieścisz je w bazie danych, będziesz w pułapce, ponieważ dane formularza nie są bezpieczne dla języka SQL! musisz obsłużyć swoją wartość formularza za pomocą mysql_real_escape_string lub jeśli używasz MySQLi mysqli :: real_escape_string lub jeśli wartość jest liczbą całkowitą lub logiczną rzutowaniem (int) (boolean)

$number = (int)$_POST['number'];
$checked = (boolean) $_POST['checked'];

$name = mysql_real_escape_string($db_pt, $_POST['name']);
$email = mysqli_obj->real_escape_string($_POST['email']);
Złupić
źródło
W moim przypadku to chyba najlepsza opcja dla mnie.
Imtiaz
6

Serializacja i nieserializacja są do tego dość powszechne. Możesz również użyć JSON za pośrednictwem json_encode i json_decode, aby uzyskać format mniej specyficzny dla PHP.

ceejayoz
źródło
5

Jak wspomniano wcześniej - jeśli nie potrzebujesz szukać danych w tablicy, możesz użyć serializacji - ale jest to „tylko php”. Dlatego polecałbym użycie json_decode / json_encode - nie tylko ze względu na wydajność, ale także czytelność i przenośność (inne języki, takie jak javascript, mogą obsługiwać dane json_encoded).

Sebastian Lasse
źródło
3

Uhh, nie wiem, dlaczego wszyscy sugerują serializację tablicy.

Mówię, że najlepszym sposobem jest dopasowanie go do schematu bazy danych. Nie mam pojęcia (i nie podałeś żadnych wskazówek) na temat rzeczywistego znaczenia semantycznego danych w twojej tablicy, ale ogólnie istnieją dwa sposoby przechowywania takich sekwencji

create table mydata (
  id int not null auto_increment primary key,
  field1 int not null,
  field2 int not null,
  ...
  fieldN int not null
)

W ten sposób przechowujesz swoją tablicę w jednym wierszu.

create table mydata (
    id int not null auto_increment primary key,
    ...
)

create table myotherdata (
    id int not null auto_increment primary key,
    mydata_id int not null,
    sequence int not null,
    data int not null
)

Wadą pierwszej metody jest oczywiście to, że jeśli masz wiele elementów w swojej tablicy, praca z tą tabelą nie będzie najbardziej elegancka. Jest również niepraktyczne (możliwe, ale również nieeleganckie - wystarczy ustawić wartości zerowe w kolumnach), aby pracować z sekwencjami o zmiennej długości.

W przypadku drugiej metody można mieć sekwencje o dowolnej długości, ale tylko jednego typu. Możesz oczywiście zrobić ten jeden typ varchar lub coś w tym stylu i serializować elementy swojej tablicy. Nie jest to najlepsza rzecz do zrobienia, ale z pewnością lepsza niż serializacja całej tablicy, prawda?

Tak czy inaczej, każda z tych metod ma wyraźną zaletę, ponieważ jest w stanie uzyskać dostęp do dowolnego elementu sekwencji i nie musisz się martwić o serializację tablic i takie brzydkie rzeczy.

Jeśli chodzi o odzyskanie go. Cóż, uzyskaj odpowiedni wiersz / sekwencję wierszy za pomocą zapytania i, cóż, użyj pętli ... prawda?

shylent
źródło
Czasami tablica naprawdę jest odpowiednia. Jeśli masz zamiar uzyskać do niego dostęp tylko jako atrybut pierwszego obiektu, ma to sens.
Matchu
1
Muszę się nie zgodzić w najostrzejszych słowach - wydaje mi się raczej niewłaściwe przechowywanie losowych, nieustrukturyzowanych („tablice” php w rzeczywistości wcale nie są tablicami, prawda?), Nietypowych bąbli danych w relacyjnej bazie danych . Czego i tak użyjesz jako separatora, jeśli twoja tablica może zawierać jakieś ciągi? To po prostu proszenie o kłopoty na wiele różnych sposobów. W 99,9% przypadków jest inny, bardziej naturalny sposób. Zrobię tu szalony domysł i zasugeruję, że przypadek pytającego nie mieści się w pozostałych 0,1%.
shylent
2
W rzeczywistości czasami bardzo dobrze jest przechowywać tablicę w polu w bazie danych. Przykładem mogą być metadane, takie jak globalna tabela „zmiennych”, w której wtyczki i moduły systemowe mogą przechowywać swoje różne ustawienia. tabelę, która przechowuje dowolne dane „sesji”, najlepiej zaimplementować przy użyciu pola zawierającego asocjacyjną tablicę kluczy / wartości. serialize i unserialize (co jest poprawną odpowiedzią) dbają o separatory. sprawdź niektóre z kilku udanych i popularnych projektów open source, takich jak WordPress lub Drupal - a zobaczysz, że tablice są czasami przechowywane w bazie danych w ten sposób
Scott Evernden,
@Scott Evernden: Myślę, że mimo wszystko masz rację. php nie jest moim „głównym” językiem, więc oceniałem rozwiązanie z perspektywy projektu bazy danych. Jeśli to, co opisujesz, jest naprawdę powszechnym sposobem robienia takich rzeczy (w php), niech tak będzie. Nie podoba mi się to :)
shylent
5
NIGDY nie jest właściwe przechowywanie tablicy w polu w bazie danych. Jest to naruszenie nie czwartej formy normalnej, trzeciej postaci normalnej lub nawet drugiej postaci normalnej: jest to NARUSZENIE PIERWSZEJ NORMALNEJ FORMY. Jeśli nie możesz zastosować się do pierwszego normalnego formularza, oznacza to, że wystąpił poważny problem z Twoim zgłoszeniem. Dotyczy to Drupala i Wordpressa; jeśli to robią, to z pewnością nie jest to spowodowane tym, że ten aspekt ich aplikacji jest dobrze zaprojektowany. Miałem ten argument w mojej ostatniej pracy, a ponieważ XCart robił te bzdury, spowodował, że coś, co powinno być możliwe, było niezwykle trudne.
Dexygen
2

Możesz zapisać swoją tablicę jako json.
istnieje dokumentacja dotycząca typu danych json: https://dev.mysql.com/doc/refman/5.7/en/json.html
Myślę, że jest to najlepsze rozwiązanie i pomoże ci utrzymać czytelność kodu, unikając szalonych funkcji .
Spodziewam się, że jest to pomocne dla Ciebie.

Roberto Murguia
źródło
0

Tak, serializacja / nieserializacja jest tym, co widziałem najczęściej w wielu projektach open source.

Eduardo
źródło
0

Sugerowałbym użycie implode / explode ze znakiem, o którym wiesz, że nie będzie zawarty w żadnym z poszczególnych elementów tablicy. Następnie zapisz go w SQL jako ciąg.

user1478500
źródło
3
To pytanie zostało zadane 3 lata temu i ma akceptowaną odpowiedź. Bardziej pomocne może być udzielenie odpowiedzi na nowsze pytania lub pytania bez odpowiedzi.
MDrollette,
0

sprawdź funkcję implode, ponieważ wartości są w tablicy, chcesz umieścić wartości tablicy w zapytaniu mysql, które wstawia wartości do tabeli.

$query = "INSERT INto hardware (specifications) VALUES (".implode(",",$specifications).")";

Jeśli wartości w tablicy są wartościami tekstowymi, należy dodać cudzysłowy

$query = "INSERT INto hardware (specifications) VALUES ("'.implode("','",$specifications)."')";

mysql_query($query);

Ponadto, jeśli nie chcesz zduplikowanych wartości, przełącz opcję „INto” na „IGNORE”, a do tabeli zostaną wstawione tylko unikalne wartości.

j0k
źródło
Jeśli masz klucz podstawowy, i tak nie otrzymasz duplikatów za pomocą polecenia INSERT INTO. Jeśli nie masz klucza podstawowego lub indeksu, IGNORE nie robi żadnej różnicy.
Peter Lindqvist
0

możesz wstawić zserializowany obiekt (tablicę) do mysql, przykład serialize($object)i możesz sprawdzić przykład obiektuunserialize($object)

Vildan Bina
źródło
-5

Zamiast zapisywać go w bazie danych, zapisz go w pliku, a następnie wywołaj później.

To, co robi wiele aplikacji php (takich jak sugarcrm), to po prostu użycie var_export do odtworzenia wszystkich danych tablicy do pliku. Oto, czego używam do zapisywania danych konfiguracji:

private function saveConfig() {
    file_put_contents($this->_data['pathtocompileddata'],'<?php' . PHP_EOL . '$acs_confdata = ' . var_export($this->_data,true) . ';');        
}

Myślę, że to lepszy sposób na zapisanie danych!

AntonioCS
źródło
To inny sposób, niekoniecznie lepszy.
Peter Lindqvist,
W rzeczy samej. Po prostu myślę, że dostęp do pliku jest znacznie łatwiejszy niż wysłanie zapytania do bazy danych w celu pobrania danych tablicy, a następnie zainicjowania tablicy. W ten sposób wystarczy dołączyć plik i gotowe.
AntonioCS