MySQLには配列変数がないようです。代わりに何を使用すればよいですか?
セット型のスカラーと一時テーブルの2つの代替案が提案されているようです。私がリンクした質問は、前者を示唆しています。しかし、配列変数の代わりにこれらを使用するのは良い習慣ですか? または、セットを使用する場合、セットベースのイディオムは何に相当しforeach
ますか?
さて、配列変数の代わりに一時テーブルを使用してきました。最大の解決策ではありませんが、うまくいきます。
フィールドを正式に定義する必要はなく、SELECT を使用して作成するだけであることに注意してください。
DROP TEMPORARY TABLE IF EXISTS my_temp_table;
CREATE TEMPORARY TABLE my_temp_table
SELECT first_name FROM people WHERE last_name = 'Smith';
( Create Table を使用せずに select ステートメントから一時テーブルを作成するも参照してください。)
WHILE
ループを使用して MySQL でこれを実現できます。
SET @myArrayOfValue = '2,5,2,23,6,';
WHILE (LOCATE(',', @myArrayOfValue) > 0)
DO
SET @value = ELT(1, @myArrayOfValue);
SET @myArrayOfValue= SUBSTRING(@myArrayOfValue, LOCATE(',',@myArrayOfValue) + 1);
INSERT INTO `EXEMPLE` VALUES(@value, 'hello');
END WHILE;
編集:代わりに、次を使用してそれを行うことができますUNION ALL
:
INSERT INTO `EXEMPLE`
(
`value`, `message`
)
(
SELECT 2 AS `value`, 'hello' AS `message`
UNION ALL
SELECT 5 AS `value`, 'hello' AS `message`
UNION ALL
SELECT 2 AS `value`, 'hello' AS `message`
UNION ALL
...
);
現在、JSON 配列を使用することは明らかな答えです。
これは古いが関連性のある質問であるため、短い例を作成しました。JSON 関数は、mySQL 5.7.x / MariaDB 10.2.3 以降で使用できます。
私は ELT() よりもこのソリューションを好みます。これは実際には配列に似ており、この「配列」をコードで再利用できるからです。
ただし、注意してください。これ (JSON) は、一時テーブルを使用するよりもはるかに低速です。その方が便利です。いも。
JSON 配列の使用方法は次のとおりです。
SET @myjson = '["gmail.com","mail.ru","arcor.de","gmx.de","t-online.de",
"web.de","googlemail.com","freenet.de","yahoo.de","gmx.net",
"me.com","bluewin.ch","hotmail.com","hotmail.de","live.de",
"icloud.com","hotmail.co.uk","yahoo.co.jp","yandex.ru"]';
SELECT JSON_LENGTH(@myjson);
-- result: 19
SELECT JSON_VALUE(@myjson, '$[0]');
-- result: gmail.com
関数/手順でどのように機能するかを示す小さな例を次に示します。
DELIMITER //
CREATE OR REPLACE FUNCTION example() RETURNS varchar(1000) DETERMINISTIC
BEGIN
DECLARE _result varchar(1000) DEFAULT '';
DECLARE _counter INT DEFAULT 0;
DECLARE _value varchar(50);
SET @myjson = '["gmail.com","mail.ru","arcor.de","gmx.de","t-online.de",
"web.de","googlemail.com","freenet.de","yahoo.de","gmx.net",
"me.com","bluewin.ch","hotmail.com","hotmail.de","live.de",
"icloud.com","hotmail.co.uk","yahoo.co.jp","yandex.ru"]';
WHILE _counter < JSON_LENGTH(@myjson) DO
-- do whatever, e.g. add-up strings...
SET _result = CONCAT(_result, _counter, '-', JSON_VALUE(@myjson, CONCAT('$[',_counter,']')), '#');
SET _counter = _counter + 1;
END WHILE;
RETURN _result;
END //
DELIMITER ;
SELECT example();
配列についてはわかりませんが、コンマ区切りのリストを通常の VARCHAR 列に格納する方法があります。
そのリストで何かを見つける必要がある場合は、FIND_IN_SET()関数を使用できます。
DELIMITER $$
CREATE DEFINER=`mysqldb`@`%` PROCEDURE `abc`()
BEGIN
BEGIN
set @value :='11,2,3,1,';
WHILE (LOCATE(',', @value) > 0) DO
SET @V_DESIGNATION = SUBSTRING(@value,1, LOCATE(',',@value)-1);
SET @value = SUBSTRING(@value, LOCATE(',',@value) + 1);
select @V_DESIGNATION;
END WHILE;
END;
END$$
DELIMITER ;
連想配列が必要な場合は、列 (キー、値) を含む一時メモリ テーブルを作成することもできます。メモリ テーブルを持つことは、mysql で配列を持つことに最も近いものです。
これが私がやった方法です。
最初に、コンマで区切られた値のリストに Long/Integer/whatever 値があるかどうかをチェックする関数を作成しました。
CREATE DEFINER = 'root'@'localhost' FUNCTION `is_id_in_ids`(
`strIDs` VARCHAR(255),
`_id` BIGINT
)
RETURNS BIT(1)
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE strLen INT DEFAULT 0;
DECLARE subStrLen INT DEFAULT 0;
DECLARE subs VARCHAR(255);
IF strIDs IS NULL THEN
SET strIDs = '';
END IF;
do_this:
LOOP
SET strLen = LENGTH(strIDs);
SET subs = SUBSTRING_INDEX(strIDs, ',', 1);
if ( CAST(subs AS UNSIGNED) = _id ) THEN
-- founded
return(1);
END IF;
SET subStrLen = LENGTH(SUBSTRING_INDEX(strIDs, ',', 1));
SET strIDs = MID(strIDs, subStrLen+2, strLen);
IF strIDs = NULL or trim(strIds) = '' THEN
LEAVE do_this;
END IF;
END LOOP do_this;
-- not founded
return(0);
END;
したがって、次のように、コンマ区切りの ID リストで ID を検索できます。
select `is_id_in_ids`('1001,1002,1003',1002);
この関数は、次のように WHERE 句内で使用できます。
SELECT * FROM table1 WHERE `is_id_in_ids`('1001,1002,1003',table1_id);
これは、「配列」パラメーターを PROCEDURE に渡す唯一の方法でした。
ELT/FIELDに言及している回答がないことに驚いています。
特に静的データがある場合、ELT/FIELD は配列と非常によく似た働きをします。
FIND_IN_SET も同様に機能しますが、補完的な機能が組み込まれていませんが、作成するのは簡単です。
mysql> select elt(2,'AA','BB','CC');
+-----------------------+
| elt(2,'AA','BB','CC') |
+-----------------------+
| BB |
+-----------------------+
1 row in set (0.00 sec)
mysql> select field('BB','AA','BB','CC');
+----------------------------+
| field('BB','AA','BB','CC') |
+----------------------------+
| 2 |
+----------------------------+
1 row in set (0.00 sec)
mysql> select find_in_set('BB','AA,BB,CC');
+------------------------------+
| find_in_set('BB','AA,BB,CC') |
+------------------------------+
| 2 |
+------------------------------+
1 row in set (0.00 sec)
mysql> SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('AA,BB,CC',',',2),',',-1);
+-----------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX('AA,BB,CC',',',2),',',-1) |
+-----------------------------------------------------------+
| BB |
+-----------------------------------------------------------+
1 row in set (0.01 sec)
配列をMySQLテーブル変数として追加したいと思って最初にここにたどり着いたので、私は尋ねます。私はデータベース設計に比較的慣れておらず、典型的なプログラミング言語のやり方でどのようにそれを行うかを考えようとしていました.
しかし、データベースは異なります。変数として配列が必要だと思っていましたが、それは一般的な MySQL データベースの慣行ではないことがわかりました。
配列の代替ソリューションは、追加のテーブルを追加してから、元のテーブルを外部キーで参照することです。
例として、家庭内のすべての人が店で購入したいすべてのアイテムを追跡するアプリケーションを想像してみましょう。
私が当初思い描いていたテーブルを作成するためのコマンドは、次のようになります。
#doesn't work
CREATE TABLE Person(
name VARCHAR(50) PRIMARY KEY
buy_list ARRAY
);
buy_list は、コンマで区切られたアイテムの文字列などになると想定していたと思います。
しかし、MySQL には配列型のフィールドがないため、次のようなものが本当に必要でした。
CREATE TABLE Person(
name VARCHAR(50) PRIMARY KEY
);
CREATE TABLE BuyList(
person VARCHAR(50),
item VARCHAR(50),
PRIMARY KEY (person, item),
CONSTRAINT fk_person FOREIGN KEY (person) REFERENCES Person(name)
);
ここで、fk_person という名前の制約を定義します。BuyList の「person」フィールドは外部キーであると書かれています。つまり、これは別のテーブルの主キーであり、具体的には Person テーブルの「name」フィールドであり、これは REFERENCES が示すものです。
また、person と item の組み合わせを主キーとして定義しましたが、技術的には必須ではありません。
最後に、人のリストのすべての項目を取得する場合は、次のクエリを実行できます。
SELECT item FROM BuyList WHERE person='John';
これにより、John のリストにあるすべての項目が表示されます。配列は必要ありません。
セットを使用する両方のバージョンが機能しませんでした (MySQL 5.5 でテスト済み)。関数 ELT() はセット全体を返します。WHILE ステートメントは PROCEDURE コンテキストでのみ使用できることを考慮して、ソリューションに追加しました。
DROP PROCEDURE IF EXISTS __main__;
DELIMITER $
CREATE PROCEDURE __main__()
BEGIN
SET @myArrayOfValue = '2,5,2,23,6,';
WHILE (LOCATE(',', @myArrayOfValue) > 0)
DO
SET @value = LEFT(@myArrayOfValue, LOCATE(',',@myArrayOfValue) - 1);
SET @myArrayOfValue = SUBSTRING(@myArrayOfValue, LOCATE(',',@myArrayOfValue) + 1);
END WHILE;
END;
$
DELIMITER ;
CALL __main__;
正直なところ、これは良い習慣ではないと思います。本当に必要な場合でも、これはほとんど読めず、かなり遅いです。
5.7.x 以降の MYSQL バージョンでは、JSON 型を使用して配列を格納できます。MYSQL を介してキーで配列の値を取得できます。
この答えを改善できると思います。これを試して:
パラメータ「いたずら」はCSVです。すなわち。「1,2,3,4.....など」
CREATE PROCEDURE AddRanks(
IN Pranks TEXT
)
BEGIN
DECLARE VCounter INTEGER;
DECLARE VStringToAdd VARCHAR(50);
SET VCounter = 0;
START TRANSACTION;
REPEAT
SET VStringToAdd = (SELECT TRIM(SUBSTRING_INDEX(Pranks, ',', 1)));
SET Pranks = (SELECT RIGHT(Pranks, TRIM(LENGTH(Pranks) - LENGTH(SUBSTRING_INDEX(Pranks, ',', 1))-1)));
INSERT INTO tbl_rank_names(rank)
VALUES(VStringToAdd);
SET VCounter = VCounter + 1;
UNTIL (Pranks = '')
END REPEAT;
SELECT VCounter AS 'Records added';
COMMIT;
END;
この方法では、CSV 値の検索文字列がループの反復ごとに徐々に短くなり、最適化に適していると思います。
PHP の serialize() を試してみましたか? これにより、変数の配列の内容を、PHP が理解し、データベースにとって安全な文字列に格納できます (最初にエスケープしたと仮定します)。
$array = array(
1 => 'some data',
2 => 'some more'
);
//Assuming you're already connected to the database
$sql = sprintf("INSERT INTO `yourTable` (`rowID`, `rowContent`) VALUES (NULL, '%s')"
, serialize(mysql_real_escape_string($array, $dbConnection)));
mysql_query($sql, $dbConnection) or die(mysql_error());
番号付き配列なしでまったく同じことを行うこともできます
$array2 = array(
'something' => 'something else'
);
また
$array3 = array(
'somethingNew'
);