Ini muncul bahwa MySQL tidak memiliki variabel array yang. Apa yang harus saya gunakan?
Tampaknya ada dua alternatif yang disarankan: Skalar tipe-set dan tabel sementara . Pertanyaan yang saya tautkan menyarankan yang pertama. Tetapi apakah praktik yang baik untuk menggunakan ini sebagai ganti variabel array? Atau, jika saya menggunakan set, apa yang akan menjadi idiom berbasis set yang setara foreach
?
ELT
.Jawaban:
Nah, saya telah menggunakan tabel sementara, bukan variabel array. Bukan solusi terhebat, tapi berhasil.
Perhatikan bahwa Anda tidak perlu menentukan bidangnya secara formal, cukup buat menggunakan SELECT:
CREATE TEMPORARY TABLE IF NOT EXISTS my_temp_table SELECT first_name FROM people WHERE last_name = 'Smith';
(Lihat juga Membuat tabel sementara dari pernyataan pilih tanpa menggunakan Buat Tabel .)
sumber
Anda dapat mencapai ini di MySQL menggunakan
WHILE
loop: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;
EDIT: Atau Anda dapat melakukannya dengan menggunakan
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 ... );
sumber
CALL
itu.UNION ALL
tanpa menggunakan prosedur.Coba gunakan fungsi FIND_IN_SET () dari MySql mis
SET @c = 'xxx,yyy,zzz'; SELECT * from countries WHERE FIND_IN_SET(countryname,@c);
Catatan: Anda tidak perlu SET variabel di StoredProcedure jika Anda meneruskan parameter dengan nilai CSV.
sumber
Saat ini menggunakan array JSON akan menjadi jawaban yang jelas.
Karena ini adalah pertanyaan lama tetapi masih relevan, saya memberikan contoh singkat. Fungsi JSON tersedia sejak mySQL 5.7.x / MariaDB 10.2.3
Saya lebih suka solusi ini daripada ELT () karena ini benar-benar lebih seperti sebuah array dan 'array' ini dapat digunakan kembali dalam kode.
Tapi hati-hati: Ini (JSON) pasti jauh lebih lambat daripada menggunakan tabel sementara. Ini hanya lebih berguna. imo.
Berikut adalah cara menggunakan array 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
Dan berikut sedikit contoh untuk menunjukkan cara kerjanya dalam suatu fungsi / prosedur:
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();
sumber
Tidak tahu tentang array, tetapi ada cara untuk menyimpan daftar yang dipisahkan koma di kolom VARCHAR normal.
Dan ketika Anda perlu menemukan sesuatu dalam daftar itu, Anda dapat menggunakan fungsi FIND_IN_SET () .
sumber
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 ;
sumber
Saya tahu bahwa ini adalah respons yang agak terlambat, tetapi baru-baru ini saya harus menyelesaikan masalah yang serupa dan berpikir bahwa ini mungkin berguna bagi orang lain.
Latar Belakang
Pertimbangkan tabel di bawah ini yang disebut 'mytable':
Masalahnya adalah menyimpan hanya 3 catatan terbaru dan menghapus semua catatan lama yang systemid = 1 (mungkin ada banyak catatan lain dalam tabel dengan nilai systemid lainnya)
Akan lebih baik jika Anda dapat melakukan ini hanya dengan menggunakan pernyataan
DELETE FROM mytable WHERE id IN (SELECT id FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3)
Namun ini belum didukung di MySQL dan jika Anda mencoba ini maka Anda akan mendapatkan kesalahan seperti
Jadi solusi diperlukan di mana array nilai diteruskan ke pemilih IN menggunakan variabel. Namun, karena variabel harus berupa nilai tunggal, saya perlu mensimulasikan sebuah array . Caranya adalah dengan membuat array sebagai daftar nilai yang dipisahkan koma (string) dan menetapkannya ke variabel sebagai berikut
SET @myvar := (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid);
Hasil yang disimpan di @myvar adalah
Selanjutnya, pemilih FIND_IN_SET digunakan untuk memilih dari larik yang disimulasikan
SELECT * FROM mytable WHERE FIND_IN_SET(id,@myvar);
Hasil akhir gabungan adalah sebagai berikut:
SET @myvar := (SELECT GROUP_CONCAT(id SEPARATOR ',') AS myval FROM (SELECT * FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3 ) A GROUP BY A.systemid); DELETE FROM mytable WHERE FIND_IN_SET(id,@myvar);
Saya sadar bahwa ini adalah kasus yang sangat spesifik. Namun dapat dimodifikasi agar sesuai dengan kasus lain di mana variabel perlu menyimpan array nilai.
Saya harap ini membantu.
sumber
Mungkin membuat tabel memori sementara dengan kolom (key, value) jika Anda menginginkan array asosiatif. Memiliki tabel memori adalah hal yang paling dekat dengan memiliki array di mysql
sumber
Begini cara saya melakukannya.
Pertama, saya membuat fungsi yang memeriksa apakah nilai Long / Integer / apa pun yang ada dalam daftar nilai yang dipisahkan dengan koma:
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;
Jadi sekarang Anda dapat mencari ID dalam daftar ID yang dipisahkan koma, seperti ini:
select `is_id_in_ids`('1001,1002,1003',1002);
Dan Anda dapat menggunakan fungsi ini di dalam klausa WHERE, seperti ini:
SELECT * FROM table1 WHERE `is_id_in_ids`('1001,1002,1003',table1_id);
Ini adalah satu-satunya cara yang saya temukan untuk meneruskan parameter "array" ke PROSEDUR.
sumber
Bukankah titik larik harus efisien? Jika Anda hanya mengulang nilai, menurut saya kursor pada tabel sementara (atau permanen) lebih masuk akal daripada mencari koma, bukan? Juga lebih bersih. Cari "mysql DECLARE CURSOR".
Untuk akses acak, tabel sementara dengan kunci utama yang diindeks secara numerik. Sayangnya akses tercepat yang akan Anda dapatkan adalah tabel hash, bukan akses acak yang sebenarnya.
sumber
Saya heran tidak ada jawaban yang menyebutkan ELT / FIELD.
ELT / FIELD bekerja sangat mirip dengan array terutama jika Anda memiliki data statis.
FIND_IN_SET juga berfungsi serupa tetapi tidak memiliki fungsi pelengkap bawaan tetapi cukup mudah untuk menulisnya.
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)
sumber
Ini berfungsi dengan baik untuk daftar nilai:
SET @myArrayOfValue = '2,5,2,23,6,'; WHILE (LOCATE(',', @myArrayOfValue) > 0) DO SET @value = ELT(1, @myArrayOfValue); SET @STR = SUBSTRING(@myArrayOfValue, 1, LOCATE(',',@myArrayOfValue)-1); SET @myArrayOfValue = SUBSTRING(@myArrayOfValue, LOCATE(',', @myArrayOfValue) + 1); INSERT INTO `Demo` VALUES(@STR, 'hello'); END WHILE;
sumber
Kedua versi yang menggunakan set tidak berfungsi untuk saya (diuji dengan MySQL 5.5). Fungsi ELT () mengembalikan seluruh set. Mempertimbangkan pernyataan WHILE hanya tersedia dalam konteks PROSEDUR, saya menambahkannya ke solusi saya:
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__;
Sejujurnya, menurut saya ini bukan praktik yang baik. Bahkan jika benar-benar diperlukan, ini hampir tidak bisa dibaca dan cukup lambat.
sumber
Cara lain untuk melihat masalah yang sama. Semoga bermanfaat
DELIMITER $$ CREATE PROCEDURE ARR(v_value VARCHAR(100)) BEGIN DECLARE v_tam VARCHAR(100); DECLARE v_pos VARCHAR(100); CREATE TEMPORARY TABLE IF NOT EXISTS split (split VARCHAR(50)); SET v_tam = (SELECT (LENGTH(v_value) - LENGTH(REPLACE(v_value,',','')))); SET v_pos = 1; WHILE (v_tam >= v_pos) DO INSERT INTO split SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(v_value,',',v_pos),',', -1); SET v_pos = v_pos + 1; END WHILE; SELECT * FROM split; DROP TEMPORARY TABLE split; END$$ CALL ARR('1006212,1006404,1003404,1006505,444,');
sumber
Dalam versi MYSQL setelah 5.7.x, Anda dapat menggunakan tipe JSON untuk menyimpan array. Anda bisa mendapatkan nilai array dengan kunci melalui MYSQL.
sumber
Terinspirasi oleh fungsi ELT (nomor indeks, string1, string2, string3,…), saya rasa contoh berikut berfungsi sebagai contoh array:
set @i := 1; while @i <= 3 do insert into table(val) values (ELT(@i ,'val1','val2','val3'...)); set @i = @i + 1; end while;
Semoga membantu.
sumber
Berikut adalah contoh MySQL untuk melakukan perulangan melalui string yang dipisahkan koma.
DECLARE v_delimited_string_access_index INT; DECLARE v_delimited_string_access_value VARCHAR(255); DECLARE v_can_still_find_values_in_delimited_string BOOLEAN; SET v_can_still_find_values_in_delimited_string = true; SET v_delimited_string_access_index = 0; WHILE (v_can_still_find_values_in_delimited_string) DO SET v_delimited_string_access_value = get_from_delimiter_split_string(in_array, ',', v_delimited_string_access_index); -- get value from string SET v_delimited_string_access_index = v_delimited_string_access_index + 1; IF (v_delimited_string_access_value = '') THEN SET v_can_still_find_values_in_delimited_string = false; -- no value at this index, stop looping ELSE -- DO WHAT YOU WANT WITH v_delimited_string_access_value HERE END IF; END WHILE;
ini menggunakan
get_from_delimiter_split_string
fungsi yang ditentukan di sini: https://stackoverflow.com/a/59666211/3068233sumber
Apakah variabel array benar-benar diperlukan?
Saya bertanya karena saya awalnya mendarat di sini ingin menambahkan array sebagai variabel tabel MySQL. Saya relatif baru dalam desain database dan mencoba memikirkan bagaimana saya akan melakukannya dengan gaya bahasa pemrograman yang khas.
Tetapi database berbeda. Saya pikir saya ingin sebuah array sebagai variabel, tetapi ternyata itu bukan praktik database MySQL yang umum.
Praktek Standar
Solusi alternatif untuk array adalah dengan menambahkan tabel tambahan, dan kemudian mereferensikan tabel asli Anda dengan kunci asing.
Sebagai contoh, mari kita bayangkan aplikasi yang melacak semua barang yang ingin dibeli setiap orang di rumah tangga di toko.
Perintah untuk membuat tabel yang awalnya saya bayangkan akan terlihat seperti ini:
#doesn't work CREATE TABLE Person( name VARCHAR(50) PRIMARY KEY buy_list ARRAY );
Saya rasa saya membayangkan buy_list menjadi string item yang dipisahkan koma atau sesuatu seperti itu.
Tetapi MySQL tidak memiliki kolom tipe array, jadi saya sangat membutuhkan sesuatu seperti ini:
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) );
Di sini kami mendefinisikan batasan bernama fk_person. Dikatakan bahwa bidang 'orang' di BuyList adalah kunci asing. Dengan kata lain, ini adalah kunci utama di tabel lain, khususnya bidang 'nama' di tabel Orang, yang ditunjukkan oleh REFERENSI.
Kami juga mendefinisikan kombinasi orang dan item menjadi kunci utama, tetapi secara teknis itu tidak perlu.
Terakhir, jika Anda ingin mendapatkan semua item di daftar seseorang, Anda dapat menjalankan kueri ini:
SELECT item FROM BuyList WHERE person='John';
Ini memberi Anda semua item di daftar John. Tidak perlu array!
sumber
Jika kita punya satu meja seperti itu
mysql> select * from user_mail; +------------+-------+ | email | user | +------------+-------+- | email1@gmail | 1 | | email2@gmail | 2 | +------------+-------+--------+------------+
dan tabel array:
mysql> select * from user_mail_array; +------------+-------+-------------+ | email | user | preferences | +------------+-------+-------------+ | email1@gmail | 1 | 1 | | email1@gmail | 1 | 2 | | email1@gmail | 1 | 3 | | email1@gmail | 1 | 4 | | email2@gmail | 2 | 5 | | email2@gmail | 2 | 6 |
Kita dapat memilih baris dari tabel kedua sebagai satu larik dengan fungsi CONCAT:
mysql> SELECT t1.*, GROUP_CONCAT(t2.preferences) AS preferences FROM user_mail t1,user_mail_array t2 where t1.email=t2.email and t1.user=t2.user GROUP BY t1.email,t1.user; +------------+-------+--------+------------+-------------+ | email | user | preferences | +------------+-------+--------+------------+-------------+ |email1@gmail | 1 | 1,3,2,4 | |email2@gmail | 2 | 5,6 | +------------+-------+--------+------------+-------------+
sumber
Saya pikir saya dapat memperbaiki jawaban ini. Coba ini:
Parameter 'Pranks' adalah CSV. yaitu. '1,2,3,4 ..... dll'
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;
Metode ini membuat string nilai CSV yang dicari semakin pendek dengan setiap iterasi loop, yang menurut saya akan lebih baik untuk pengoptimalan.
sumber
Saya akan mencoba sesuatu seperti ini untuk beberapa koleksi. Saya seorang pemula MySQL. Maaf tentang nama fungsi, tidak bisa memutuskan nama mana yang terbaik.
delimiter // drop procedure init_ // create procedure init_() begin CREATE TEMPORARY TABLE if not exists val_store( realm varchar(30) , id varchar(30) , val varchar(255) , primary key ( realm , id ) ); end; // drop function if exists get_ // create function get_( p_realm varchar(30) , p_id varchar(30) ) returns varchar(255) reads sql data begin declare ret_val varchar(255); declare continue handler for 1146 set ret_val = null; select val into ret_val from val_store where id = p_id; return ret_val; end; // drop procedure if exists set_ // create procedure set_( p_realm varchar(30) , p_id varchar(30) , p_val varchar(255) ) begin call init_(); insert into val_store (realm,id,val) values (p_realm , p_id , p_val) on duplicate key update val = p_val; end; // drop procedure if exists remove_ // create procedure remove_( p_realm varchar(30) , p_id varchar(30) ) begin call init_(); delete from val_store where realm = p_realm and id = p_id; end; // drop procedure if exists erase_ // create procedure erase_( p_realm varchar(30) ) begin call init_(); delete from val_store where realm = p_realm; end; // call set_('my_array_table_name','my_key','my_value'); select get_('my_array_table_name','my_key');
sumber
Daripada Menyimpan data sebagai array atau hanya dalam satu baris, Anda harus membuat baris yang berbeda untuk setiap nilai yang diterima. Ini akan membuatnya lebih sederhana untuk dipahami daripada menyatukan semuanya.
sumber
Sudahkah Anda mencoba menggunakan serialize () PHP? Itu memungkinkan Anda untuk menyimpan konten array variabel dalam string yang dipahami PHP dan aman untuk database (dengan asumsi Anda telah lolos terlebih dahulu).
$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());
Anda juga dapat melakukan hal yang sama tanpa larik bernomor
atau
sumber