Jak mogę symulować zmienną array w MySQL?
Wydaje się , że MySQL nie ma zmiennych tablicowych. Czego powinienem użyć zamiast tego?
Sugerowane są dwie alternatywy: Skalar typu set itabele tymczasowe . Pytanie, które podlinkowałem, sugeruje to pierwsze. Ale czy jest to dobra praktyka, aby używać tych zmiennych zamiast tablic? Alternatywnie, jeśli pójdę z zestawami, jaki byłby idiom oparty na zestawach równoważny foreach
?
16 answers
Cóż, używam tabel tymczasowych zamiast zmiennych tablicowych. Nie najlepsze rozwiązanie, ale działa.
Zauważ, że nie musisz formalnie definiować ich pól, po prostu utwórz je za pomocą SELECT:
CREATE TEMPORARY TABLE IF NOT EXISTS my_temp_table
SELECT first_name FROM people WHERE last_name = 'Smith';
(Patrz również Tworzenie tymczasowej tabeli z instrukcji select bez użycia Create Table .)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:15
Możesz to osiągnąć w MySQL używając pętli WHILE
:
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;
Edytuj:
Alternatywnie możesz to zrobić używając 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
...
);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-21 08:08:27
Spróbuj użyć funkcji FIND_IN_SET () MySql np.
SET @c = 'xxx,yyy,zzz';
SELECT * from countries
WHERE FIND_IN_SET(countryname,@c);
Uwaga: nie musisz ustawiać zmiennej w StoredProcedure, jeśli przekazujesz parametr z wartościami CSV.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-14 09:15:54
Nie wiem o tablicach, ale istnieje sposób na przechowywanie list rozdzielonych przecinkami w zwykłej kolumnie VARCHAR.
I kiedy chcesz znaleźć coś na tej liście, możesz użyć funkcji FIND_IN_SET () .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-26 21:45:38
Może utworzyć tymczasową tabelę pamięci z kolumnami (klucz, wartość), jeśli chcesz tablic asocjacyjnych. Posiadanie tablicy pamięci jest najbliższą rzeczą do posiadania tablic w mysql
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-01 08:05:52
Oto Jak to zrobiłem.
Najpierw stworzyłem funkcję, która sprawdza, czy Long / Integer / whatever value znajduje się na liście wartości oddzielonych przecinkami:
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;
Więc teraz możesz wyszukać ID na oddzielonej przecinkami liście Id, jak to:
select `is_id_in_ids`('1001,1002,1003',1002);
I możesz użyć tej funkcji wewnątrz klauzuli WHERE, jak to:
SELECT * FROM table1 WHERE `is_id_in_ids`('1001,1002,1003',table1_id);
To był jedyny sposób na przekazanie parametru" array " do procedury.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-20 14:36:49
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 ;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-03 11:55:27
Obecnie użycie tablicy JSON byłoby oczywistą odpowiedzią.
Ponieważ jest to stare, ale wciąż aktualne pytanie, przedstawiłem krótki przykład. Funkcje JSON są dostępne od mySQL 5.7.x / MariaDB 10.2.3
Wolę to rozwiązanie niż ELT (), ponieważ jest to bardziej tablica i ta 'tablica' może być ponownie użyta w kodzie.
ale uważaj: to (JSON) jest z pewnością znacznie wolniejsze niż używanie tabeli tymczasowej. Jest po prostu bardziej poręczny. imo.
Tutaj jest jak używać tablicy 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
A tutaj mały przykład, aby pokazać, jak to działa w funkcji / procedurze:
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();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-15 08:34:52
To działa dobrze dla listy wartości:
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;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-21 15:44:45
Obie wersje używające zestawów nie działały dla mnie (testowane z MySQL 5.5). Funkcja ELT () zwraca cały zestaw. Biorąc pod uwagę, że instrukcja WHILE jest dostępna tylko w kontekście procedury, dodałem ją do mojego rozwiązania:
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__;
Szczerze mówiąc, nie sądzę, żeby to była dobra praktyka. Nawet jeśli jest to naprawdę konieczne, jest to ledwo czytelne i dość powolne.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-30 10:04:23
Czy sens tablic nie jest skuteczny? Jeśli tylko iterujesz wartości, myślę, że kursor na tymczasowej (lub stałej) tabeli ma więcej sensu niż szukanie przecinków, nie? Również czystsze. Lookup "mysql DECLARE CURSOR".
Dla dostępu losowego tymczasowa tabela z numerycznie indeksowanym kluczem głównym. Niestety najszybszy dostęp otrzymasz jest tabela hash, a nie prawdziwy dostęp losowy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-26 21:18:45
W MYSQL w wersji po 5.7.x, możesz użyć JSON type do przechowywania tablicy. Wartość tablicy można uzyskać za pomocą klucza poprzez MYSQL.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 00:48:34
Zainspirowany funkcją ELT (Numer indeksu, string1, string2, string3,...), myślę, że poniższy przykład działa jako przykład tablicy:
set @i := 1;
while @i <= 3
do
insert into table(val) values (ELT(@i ,'val1','val2','val3'...));
set @i = @i + 1;
end while;
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-02 08:36:47
Wiem, że jest to trochę spóźniona odpowiedź, ale ostatnio musiałem rozwiązać podobny problem i pomyślałem, że może to być przydatne dla innych.
Tło
Rozważmy poniższą tabelę nazwaną "mytable":
Problem polegał na przechowywaniu tylko ostatnich 3 rekordów i usuwaniu starszych rekordów, których systemid=1 (w tabeli może być wiele innych rekordów z innymi wartościami systemid)
Byłoby dobrze, gdybyś mógł to zrobić po prostu korzystanie z instrukcji
DELETE FROM mytable WHERE id IN (SELECT id FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3)
Jednak nie jest to jeszcze obsługiwane w MySQL i jeśli spróbujesz tego, otrzymasz błąd jak
...doesn't yet support 'LIMIT & IN/ALL/SOME subquery'
Dlatego potrzebne jest obejście, w którym tablica wartości jest przekazywana do selektora IN przy użyciu zmiennej. Jednak, ponieważ zmienne muszą być pojedynczymi wartościami, musiałbym symulować tablicę. sztuką jest utworzenie tablicy jako oddzielonej przecinkami listy wartości (string) i przypisanie jej do zmiennej w następujący sposób
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);
The wynik zapisany w @myvar to
5,6,7
Następnie selektor FIND_IN_SET służy do wyboru z symulowanej tablicy
SELECT * FROM mytable WHERE FIND_IN_SET(id,@myvar);
Łączny wynik końcowy jest następujący:
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);
Zdaję sobie sprawę, że jest to bardzo szczególny przypadek. Można go jednak zmodyfikować tak, aby pasował do każdego innego przypadku, w którym zmienna musi przechowywać tablicę wartości.
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-18 09:50:42
Myślę, że mogę poprawić tę odpowiedź. Spróbuj tego:
Parametr "Pranks" jest plikiem CSV. ie. '1,2,3,4.....etc "
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;
Ta metoda sprawia, że wyszukiwany ciąg wartości CSV jest coraz krótszy z każdą iteracją pętli, co moim zdaniem byłoby lepsze dla optymalizacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-26 11:29:26
Próbowałeś użyć funkcji serialize () PHP? To pozwala na przechowywanie zawartości tablicy zmiennej w łańcuchu znaków PHP rozumie i jest bezpieczne dla bazy danych(zakładając, że wcześniej ją uniknąłeś).
$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());
Możesz również zrobić dokładnie to samo bez tablicy numerowanej
$array2 = array(
'something' => 'something else'
);
Lub
$array3 = array(
'somethingNew'
);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-23 13:45:35