PHP配列をMySQLに保存しますか?


88

データの配列を単一のmysqlフィールドに保存する良い方法は何ですか?

また、mysqlテーブルでその配列をクエリしたら、それを配列形式に戻す良い方法は何ですか?

答えをシリアライズおよびシリアライズ解除しますか?

回答:


87

配列を単一のフィールドに格納する良い方法はありません。

リレーショナルデータを調べて、スキーマに適切な変更を加える必要があります。このアプローチのリファレンスについては、以下の例を参照してください。

配列を単一のフィールドに保存する必要がある場合はserialize()unserialize()関数でうまくいきます。ただし、実際のコンテンツに対してクエリを実行することはできません。

シリアル化関数の代替として、json_encode()およびも ありjson_decode()ます。

次の配列を考えます

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

データベースに保存するには、次のようなテーブルを作成する必要があります

$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)
    )');

レコードを操作するには、次のようなクエリを実行できます(これは一例です。注意してください)。

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()関数は、MySQLの接続リソースを返します。

function connect() {
    $c = mysql_connect($server, $username, $password);
    mysql_select_db('test');
    return $c;
}

26

一般的には、はい、シリアライズとアンシリアライズする方法です。

ただし、データが単純なものである場合は、コンマ区切りの文字列として保存することをお勧めします。たとえば、配列が数値のリストになることがわかっている場合は、implode / explodeを使用する必要があります。それは違います1,2,3a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}

そうでない場合は、すべてのケースで作業をシリアライズおよびシリアライズ解除します。


22
ここにいる読者の皆さん、私は時間をかけて、長年の経験を通じて、これが実際に進むべき道ではないことを発見したことを発表します。受け入れられた答えは、はるかに強力なアプローチです。
Matchu

4
あなたがここにいるサイン、読者があなたと共有するのは、それは単にあなたの要件に依存するということです。配列値でクエリを実行する必要がなく、非常に高速なものが必要な場合は、このようなデータを単一のフィールドに安全に格納でき(これは質問が明確に述べていることです)、主キーをたたいて、すぐに使用できます。アプリケーションが何であるか疑問に思う場合:5分ごとにcronされるキューにデータをプッシュします。別のcronは、はるかに時間がかかる配列を作成します。クエリは計算されたデータをフェッチし、それをサードパーティのAPIに渡します。それを行うためのより良い方法はありません。
2015

1
@RidIculous混乱しています、あなたはあなた自身の個人的なアプリケーション、または質問された原因となったアプリケーションについて話していますか?
Peter Lindqvist 2015

1
それは私の声明の前提とは関係ありませんが、「アプリケーションが何であるか疑問に思うなら」という接頭辞は明確にする必要があります。
Iculousを

10

PHP関数のシリアライズを使用するだけです。

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

ただし、そのような単純な配列を使用している場合は、implodeとexplodeを使用することもできます。newではなく空の配列を使用してください。


9

DBに格納するための配列のシリアル化/シリアル化解除

http://php.net/manual/en/function.serialize.phpにアクセスします

PHPマニュアルから:

ページの「返品」をご覧ください

どこにでも格納できる値のバイトストリーム表現を含む文字列を返します。

これはnullバイトを含む可能性があるバイナリ文字列であり、そのように格納および処理する必要があることに注意してください。たとえば、serialize()出力は、通常、CHARまたはTEXTフィールドではなく、データベースのBLOBフィールドに格納する必要があります。

注:HTMLをBLOBに保存する場合は、Base64でエンコードしてください。そうしないと、シリアライズ機能が動作しなくなる可能性があります。

エンコーディングの例:

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

$YourSerializedData これでb​​lobに保存する準備ができました。

blobからデータを取得したら、base64_decodeを実行してから、サンプルのデコードをシリアル化解除する必要があります。

$theHTML = unserialize(base64_decode($YourSerializedData));

8

私が自分で見つけた最良の方法は、区切り文字を含むデータ文字列として配列を保存することです

$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 . "');";

その後、単純なクエリで配列に格納されたデータを検索できます

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

explode()関数を使用して、「array_data」文字列を配列に変換します

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

これは多次元配列では機能しないことに注意してください。「array_separator」が一意であり、配列値に存在していないことを確認してください。

注意してください !!!フォームデータを取得してデータベースに入れるだけでは、フォームデータはSQLセーフではないため、罠にかかってしまいます。フォームの値はmysql_real_escape_stringで処理する必要があります。MySQLimysqli :: real_escape_stringを使用する場合、 または値が整数またはブールキャスト(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']);

私の場合、これが私にとって最良のオプションだと思います。
Imtiaz 14

6

そのため、シリアライズとアンシリアライズはかなり一般的です。また、PHP固有ではない形式のjson_encodeおよびjson_decodeを介してJSONを使用することもできます。


5

前述のように、配列内のデータを検索する必要がない場合は、serializeを使用できますが、これは「phpのみ」です。だから私はjson_decode / json_encodeを使用することをお勧めします-パフォーマンスだけでなく可読性と移植性のためにも(javascriptなどの他の言語はjson_encodedデータを処理できます)。


3

ええと、なぜ誰もがアレイのシリアル化を提案する理由がわかりません。

私が言うには、最良の方法は実際にデータベーススキーマに適合させることです。私はあなたの配列のデータの実際の意味の意味についてはわかりません(そしてあなたは手がかりを与えませんでした)が、一般的にそのようなシーケンスを格納する2つの方法があります

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

このようにして、配列を単一の行に格納します。

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
)

最初の方法の欠点は、配列に多くのアイテムがある場合、そのテーブルでの作業が最も洗練されたものにならないことです。可変長のシーケンスを処理することも非現実的です(可能ですが、非常に洗練されていません。列をnullにするだけです)。

2番目の方法では、任意の長さのシーケンスを持つことができますが、タイプは1つだけです。もちろん、1つのタイプのvarcharなどを作成して、配列の項目をシリアル化できます。最善の方法ではありませんが、アレイ全体をシリアル化するよりも確かに優れていますよね?

どちらの方法でも、このメソッドにはシーケンスの任意の要素にアクセスできるという明確な利点があり、配列のシリアル化やそのような醜いことを心配する必要はありません。

それを取り戻すことに関しては。さて、クエリを使用して適切な行/行のシーケンスを取得し、ループを使用してください


時々配列は本当に適切です。最初のオブジェクトの属性としてのみアクセスする場合、それは理にかなっています。
マッチュ2009

1
私は最も厳しい条件で意見を異にする必要があります- リレーショナルデータベースにランダムな、構造化されていない(php "配列"は実際には配列ではありません)、型付けされていないデータのブロブを格納するのはかなり不適切に思われます。配列に文字列が含まれている可能性がある場合、とにかくセパレータに何を使用しますか?これは、さまざまな方法でトラブルを求めているだけです。99,9%のケースでは、別のより自然な方法があります。ここで大まかな推測をして、質問者のケースが残りの0.1%に該当しないことを示唆します。
shylent 2009

2
実際には、DBのフィールドに配列を格納することが非常に適切な場合があります。例としては、システムのプラグインとモジュールがさまざまな設定を格納できるグローバルな「変数」テーブルのようなメタデータがあります。任意の「セッション」データを格納するテーブルは、キー/値の連想配列を保持するフィールドを使用して実装するのが最適です。シリアライズとアンシリアライズ(正解)は、セパレーターを処理します。WordPressやDrupalなど、成功し人気のあるいくつかのオープンソースプロジェクトのいくつかを確認すると、配列が次のようにDBに保存される場合があります
Scott Evernden

@Scott Evernden:結局のところ、あなたは正しいと思います。phpは私の「メイン」言語ではないので、データベース設計の観点からソリューションを判断しました。あなたが説明するものが本当に(phpで)そのようなことをするための一般的な方法であるなら、そうなるでしょう。でも私には気に入らない:)
shylent 09/12/30

5
DBのフィールドに配列を格納することは決して適切ではありません。これは、第4正規形、第3正規形、さらには第2正規形の違反ではありません。これは、第1正規形の違反です。最初の通常の形式にさえ従うことができない場合、アプリケーションに深刻な問題があります。それはDrupalとWordpressにも当てはまります。彼らがこれを行うなら、それは確かにそうではありません。そのアプリのファセットは適切に設計されているからです。私は最後の仕事でこの議論をしました。
Dexygen、2009

2

配列をjsonとして保存できます。
jsonデータ型のドキュメントがあります:https ://dev.mysql.com/doc/refman/5.7/en/json.html
これは最良の解決策だと思います。クレイジーな関数を回避することで、コードを読みやすくするのに役立ちます。
これはあなたに役立つと思います。


0

うん、serialize / unserializeは、多くのオープンソースプロジェクトで最もよく目にしたものです。


0

個々の配列項目のいずれにも含まれないことがわかっている文字で、分解/分解を使用することをお勧めします。次に、それを文字列としてSQLに保存します。


3
この質問は3年前に尋ねられ、受け入れられた回答があります。新しい質問や回答のない質問に回答する方が役立つ場合があります。
MDrollette 2012年

0

値が配列に含まれているため、関数implodeを確認してください。配列の値を、テーブルに値を挿入するmysqlクエリに入れます。

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

配列の値がテキスト値の場合、引用符を追加する必要があります

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

mysql_query($query);

また、重複する値が必要ない場合は、「INto」を「IGNORE」に切り替えると、一意の値のみがテーブルに挿入されます。


主キーがある場合は、とにかくINSERT INTOを使用して重複を取得することはありません。主キーまたはインデックスがない場合、IGNOREは違いを生じません。
Peter Lindqvist

0

シリアライズされたオブジェクト(配列)をmysqlに挿入し、serialize($object)オブジェクトの例を逆シリアル化できます。unserialize($object)


-5

データベースに保存する代わりに、ファイルに保存して、後で呼び出します。

多くのphpアプリが行うこと(sugarcmなど)は、var_exportを使用して配列のすべてのデータをファイルにエコーすることです。これは、構成データを保存するために使用するものです。

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

これはあなたのデータを保存するためのより良い方法だと思います!


これは別の方法であり、必ずしも優れているとは限りません。
Peter Lindqvist

確かに。ファイルにアクセスする方が、データベースにクエリを実行して配列データを取得し、配列を初期化するよりもはるかに簡単だと思います。このように、ファイルを含めるだけで完了です。
AntonioCS 2009
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.