MYSQL Truncated incorrect DOUBLE value - mysql

When the SQL query below is executed:
UPDATE shop_category
SET name = 'Secolul XVI - XVIII'
AND name_eng = '16th to 18th centuries'
WHERE category_id = 4768
The following error is raised:
1292 - Truncated incorrect DOUBLE value: 'Secolul XVI - XVIII'
How to fix this?
shop_category table structure:
category_id mediumint(8)
name varchar(250)
name_eng varchar(250)

You don't need the AND keyword. Here's the correct syntax of the UPDATE statement:
UPDATE
shop_category
SET
name = 'Secolul XVI - XVIII',
name_eng = '16th to 18th centuries'
WHERE
category_id = 4768

I was getting this exception not because of AND instead of comma, in fact I was having this exception just because I was not using apostrophes in where clause.
Like my query was
update table set coulmn1='something' where column2 in (00012121);
when I changed where clause to where column2 in ('00012121'); then the query worked fine for me.

What it basically is
It's incorrect syntax that causes MySQL to think you're trying to do something with a column or parameter that has the incorrect type "DOUBLE".
Learn from my mistake
In my case I updated the varchar column in a table setting NULL where the value 0 stood. My update query was like this:
UPDATE myTable SET myValue = NULL WHERE myValue = 0;
Now, since the actual type of myValue is VARCHAR(255) this gives the warning:
+---------+------+-----------------------------------------------+
| Level | Code | Message |
+---------+------+-----------------------------------------------+
| Warning | 1292 | Truncated incorrect DOUBLE value: 'value xyz' |
+---------+------+-----------------------------------------------+
And now myTable is practically empty, because myValue is now NULL for EVERY ROW in the table! How did this happen?
*internal screaming*
Over 30k rows now have missing data.
*internal screaming intensifies*
Thank goodness for backups. I was able to recover all the data.
*internal screaming intensity lowers*
The corrected query is as follows:
UPDATE myTable SET myValue = NULL WHERE myValue = '0';
^^^
Quotation here!
I wish this was more than just a warning so it's less dangerous to forget those quotes.
*End internal screaming*

Try replacing the AND with ,
UPDATE shop_category
SET name = 'Secolul XVI - XVIII', name_eng = '16th to 18th centuries'
WHERE category_id = 4768
The UPDATE Syntax shows comma should be used as the separator.

Mainly invalid query strings will give this warning.
Wrong due to a subtle syntax error (misplaced right parenthesis) when using INSTR function:
INSERT INTO users (user_name) SELECT name FROM site_users WHERE
INSTR(status, 'active'>0);
Correct:
INSERT INTO users (user_name) SELECT name FROM site_users WHERE
INSTR(status, 'active')>0;

I just wasted my time on this and wanted to add an additional case where this error presents itself.
SQL Error (1292): Truncated incorrect DOUBLE value: 'N0003'
Test data
CREATE TABLE `table1 ` (
`value1` VARCHAR(50) NOT NULL
);
INSERT INTO table1 (value1) VALUES ('N0003');
CREATE TABLE `table2 ` (
`value2` VARCHAR(50) NOT NULL
);
INSERT INTO table2 (value2)
SELECT value1
FROM table1
WHERE 1
ORDER BY value1+0
The problem is ORDER BY value1+0 - type casting.
I know that it does not answer the question but this is the first result on Google for this error and it should have other examples where this error presents itself.

It seems mysql handles the type casting gracefully with SELECT statements.
The shop_id field is of type varchar but the select statements works
select * from shops where shop_id = 26244317283;
But when you try updating the fields
update stores set store_url = 'https://test-url.com' where shop_id = 26244317283;
It fails with error Truncated incorrect DOUBLE value: '1t5hxq9'
You need to put the shop_id 26244317283 in quotes '26244317283' for the query to work since the field is of type varchar not int
update stores set store_url = 'https://test-url.com' where shop_id = '26244317283';

1292 - Truncated incorrect DOUBLE value:
This error occurs when you try to compare different types on SQL like `uniqueid` = 1610386969.1713 in this query:
UPDATE `cdr` SET `userfield`='survey=5,' WHERE `uniqueid` = 1610386969.1713
change it for passing the error on this UPDATE example:
UPDATE `cdr` SET `userfield`='survey=5,' WHERE `uniqueid` = '1610386969.1713'
But in your problem, if you change the AND to , the problem will be resolved
UPDATE shop_category SET name = 'Secolul XVI - XVIII', name_eng = '16th to 18th centuries' WHERE category_id = 4768

This is because of "and" in-between while using update query
WRONG ==> "update user_detail set name = ? and phone_code = ? and phone_num = ? and email = ? where emp_code = ?";
instead of this use COMMA(,)
RIGHT ==> "update user_detail set name = ?, phone_code = ?, phone_number = ?, email = ? where emp_code = ?"

If you're getting this problem with an insert that looks like the one below, the problem may simply be the lack of a space between -- and the comment text:
insert into myTable (a, b, c)
values (
123 --something
,345 --something else
,567 --something something else
);
The problem with this is that the --something should actually be -- something with a space.

I experienced this error when using bindParam, and specifying PDO::PARAM_INT where I was actually passing a string. Changing to PDO::PARAM_STR fixed the error.

I did experience this error when I tried doing an WHERE EXIST where the subquery matched 2 columns that accidentially was different types.
The two tables was also different storage engines.
One column was a CHAR (90) and the other was a BIGINT (20).
One table was InnoDB and the other was MEMORY.
Part of query:
[...] AND EXISTS (select objectid from temp_objectids where temp_objectids.objectid = items_raw.objectid );
Changing the column type on the one column from BIGINT to CHAR solved the issue.

// CALL `ut_liquid_name_maildt`() Edit
// Truncated incorrect DOUBLE value: 'IPPAGUNTA VIJAYALAKSHMI'
// Code Sample
BEGIN
-- Declare loop constructs --
DECLARE done INT DEFAULT FALSE;
DECLARE my_id VARCHAR(50);
DECLARE my_name VARCHAR(50);
DECLARE my_mail_dt date;
DECLARE my_name_gl VARCHAR(50);
DECLARE my_mail_dt_gl VARCHAR(50);
-- cursor --
declare cr cursor for select t2.id,t1.name,t1.mail_dt,t2.name as name_gl,t2.mail_dt as mail_dt_gl
from sch_acc_saleint as t1
inner join
sch_acc_salegl as t2
where t1.sch_batch = t2.sch_batch;
-- Declare Continue Handler --
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cr;
read_loop: LOOP
-- Fetch data from cursor --
FETCH cr
INTO my_id,my_name,my_mail_dt,my_name_gl,my_mail_dt_gl;
-- Exit loop if finished --
IF done THEN
LEAVE read_loop;
END IF;
-- Update Query --
UPDATE sch_acc_salegl SET name = my_name and mail_dt = my_mail_dt WHERE id = my_id;
END LOOP read_loop;
CLOSE cr;
END
// I was using wrong update query that"s why it is showing error [ Truncated incorrect DOUBLE value ]
// For this type of error check update query
// For example :
UPDATE sch_acc_salegl SET name = my_name,mail_dt = my_mail_dt WHERE id = my_id;

In my case it was a Dreamweaver function that sanitizes the data before running mysql queries:
GetSQLValueString($my_string, "text")
by mistake I had it as:
GetSQLValueString($my_string, "int")
Basically converting my string to an integer then trying to run MySQL queries based on that. When it should have been a string.
So using "int" instead of "text" caused the problem for me.

Related

MySQL : Stored procedure returns null for last_insert_id

I'm facing a problem with SP in mySql when I want to select my identete it gives always null as value.
DELIMITER $$
CREATE PROCEDURE insert_details_facture(IN typefacture INT,
IN codeactivite VARCHAR(255),
IN qte INT,
IN pu DOUBLE,
IN unite VARCHAR(255),
IN montant DOUBLE)
BEGIN
DECLARE identete INT;
SELECT identete = numfacture FROM entetefacture WHERE numfacture = LAST_INSERT_ID();
END$$
When I execute this it gives identite = numfacture as column's name and null as value.
CALL insert_details_facture(10,'l',10,12,'l',20)
Check Here.
With no argument, LAST_INSERT_ID() returns a BIGINT UNSIGNED (64-bit) value representing the first automatically generated value successfully inserted for an AUTO_INCREMENT column as a result of the most recently executed INSERT statement.
so result you are getting is obvious.
to get last record you can use limit.
SET identete = (SELECT numfacture FROM entetefacture ORDER BY id DESC LIMIT 1);
LAST_INSERT_ID() is not guaranteed to have a valid value. For instance, the documentation states:
If the previous statement returned an error, the value of
LAST_INSERT_ID() is undefined. For transactional tables, if the
statement is rolled back due to an error, the value of
LAST_INSERT_ID() is left undefined.
Similarly, if there have been no database changes for the current session, then the value will be undefined.
Also, if you want to set the value, then use := in a select:
SELECT identete := numfacture
FROM entetefacture
WHERE numfacture = LAST_INSERT_ID();
Why not just get the last row in the table using limit?
SET identete = (SELECT numfacture FROM entetefacture ORDER BY id LIMIT 1);

mysql different row updates depending on a variable (stored procedure)

CREATE PROCEDURE update_table(
IN choice INT(4),
IN id VARCHAR(50),
IN string VARCHAR(50)
)
BEGIN
UPDATE salesman
set salesman_name = IF(choice = 1, string, salesman_name)
where salesman_id = id
UPDATE salesman
set date = IF(choice = 2, string, date)
where salesman_id = id
END
if choiceis 1, change salesman_name as string
if choice is 2, change date as string
can you explain me what i'm doing wrong?
it works fine with a single update, my guess is there is another way to implement if but i couldn't.
if choice = 1 then
update salesman set salesman_name = string where salesman_id = id
...i tried this version too but still, not working.
DELIMITER //
CREATE PROCEDURE update_table(
IN choice INT(4),
IN id VARCHAR(50),
IN string VARCHAR(50)
)
BEGIN
UPDATE salesman set salesman_name = IF(choice = 1, string, salesman_name) where salesman_id = id;
UPDATE salesman set date = IF(choice = 2, string, date) where salesman_id = id;
END //
DELIMITER ;
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER' at line 1
also says this:
ERROR: Unknown Punctuation String # 11 (last line)
When a stored procedure has more than one statement, they need to be terminated with ;
To do that, you need to tempoararily change the delimiter so you can end the procedure. Here's a SO answer with an example of how to do that: MySQL create stored procedure syntax with delimiter

How to update all rows for a column

I am trying to update multiple rows on one column (SQL Server 2008). The column I need to update has insert and update trigger. When I run this script I got an error message:
UPDATE htable
SET Isverified=1
WHERE columnname IN ('122','566','652')
Error:
Msg 512, Level 16, State 1, Procedure mydatabasename, Line 22
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I don't know how true this is but I want to believe due to the trigger define on this column. Did any want know how I can achieve this
here is the trigger:
ALTER TRIGGER [dbo].[sendTodbase]
ON [dbo].[htable]
AFTER UPDATE
AS
BEGIN DISTRIBUTED TRANSACTION
SET NOCOUNT ON
--CHECK IF DATAENTRY COLUMN IS UPDATED
IF UPDATE(Isverified) begin
declare #dEVer bit declare #rcNum varchar(50)
declare #idenNum varchar(50) declare #docId bigint
--GET INSERTED VALUE AND CHECK IF IT's (YES) THEN CONTINUE...
select #dEVer = (select Isverified from inserted i)
if #dEVer = 1 begin
--END CHECK, IF DE IS COMPLETED CONTINUE----
COMMIT TRAN
Exception is probably generated by:
select #dEVer = (select Isverified from inserted i)
TSQL interpreter expects no more than one row returned by select Isverified from inserted i subquery.
Your update query affets more than one row and exception Subquery returned more than 1 value is generated.
Try Something like this:
Update mydatble set ColumnName = <Require value>
where columnname in ('122','566','652')

How to make MySQL produce an error if value not specified on NOT NULL Columns?

Let's assume that I have a NOT NULL column in a table,
How can I make MySQL to produce an error if such statement is used?
INSERT INTO tableName () VALUES ();
Thank you.
To set a column to not null use this syntax :
ALTER TABLE table_name
MODIFY column_name [data type] NOT NULL;
If you column is declared not null an error will be produced !!
If you want a customized error msg then you need to create trigger action !
Here is a trigger that can help you :
DELIMITER $$
CREATE TRIGGER trgBEFORE UPDATE ON `tbl`
FOR EACH ROW BEGIN
declare msg varchar(255);
IF (NEW.col1IS NULL ) THEN
set msg = concat('MyTriggerError: Trying to insert a null value );
signal sqlstate '45000' set message_text = msg;
ELSE
SET NEW.col1= NEW.col1);
END IF;
END$$
DELIMITER ;
I know this is late but it might help someone.
You can set the SQL mode, either in the configuration file or at runtime for current session.
To produce the error you need to enable strict sql mode with:
SET GLOBAL sql_mode = 'STRICT_ALL_TABLES'; or SET GLOBAL sql_mode = 'STRICT_TRANS_TABLES';
Here is a link for more information on sql modes.
How to make MySQL produce an error, when inserting a row to a table containing NOT NULL column, when not specifying a value to that column like in "INSERT INTO tableName () VALUES()".
Is there a way without a trigger?
This is possible without a trigger only when you define no default when defining a column. Also the same is applicable for alter ... column ...
Example 1:
create table ck_nn( i int not null );
insert into ck_nn values();
The above insert throws an error as no default is defined on the column.
Message can be something like Field 'i' doesn't have a default value.
Example 2:
create table ck_nn2( i2 int not null default 999 );
insert into ck_nn2 values();
The above insert won't throw any error as default value is defined on the column.
select * from ck_nn2;
+-----+
| i2 |
+-----+
| 999 |
+-----+
Example # SQL Fiddle

How can I simulate an array variable in MySQL?

It appears that MySQL doesn't have array variables. What should I use instead?
There seem to be two alternatives suggested: A set-type scalar and temporary tables. The question I linked to suggests the former. But is it good practice to use these instead of array variables? Alternatively, if I go with sets, what would be the set-based idiom equivalent to foreach?
Well, I've been using temporary tables instead of array variables. Not the greatest solution, but it works.
Note that you don't need to formally define their fields, just create them using a SELECT:
DROP TEMPORARY TABLE IF EXISTS my_temp_table;
CREATE TEMPORARY TABLE my_temp_table
SELECT first_name FROM people WHERE last_name = 'Smith';
(See also Create temporary table from select statement without using Create Table.)
You can achieve this in MySQL using 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:
Alternatively you can do it using 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
...
);
Try using FIND_IN_SET() function of MySql
e.g.
SET #c = 'xxx,yyy,zzz';
SELECT * from countries
WHERE FIND_IN_SET(countryname,#c);
Note: You don't have to SET variable in StoredProcedure if you are passing parameter with CSV values.
Nowadays using a JSON array would be an obvious answer.
Since this is an old but still relevant question I produced a short example.
JSON functions are available since mySQL 5.7.x / MariaDB 10.2.3
I prefer this solution over ELT() because it's really more like an array and this 'array' can be reused in the code.
But be careful: It (JSON) is certainly much slower than using a temporary table. Its just more handy. imo.
Here is how to use a JSON array:
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
And here a little example to show how it works in a function/procedure:
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();
Dont know about the arrays, but there is a way to store comma-separated lists in normal VARCHAR column.
And when you need to find something in that list you can use the FIND_IN_SET() function.
I know that this is a bit of a late response, but I recently had to solve a similar problem and thought that this may be useful to others.
Background
Consider the table below called 'mytable':
The problem was to keep only latest 3 records and delete any older records whose systemid=1 (there could be many other records in the table with other systemid values)
It would be good if you could do this simply using the statement
DELETE FROM mytable WHERE id IN (SELECT id FROM `mytable` WHERE systemid=1 ORDER BY id DESC LIMIT 3)
However this is not yet supported in MySQL and if you try this then you will get an error like
...doesn't yet support 'LIMIT & IN/ALL/SOME subquery'
So a workaround is needed whereby an array of values is passed to the IN selector using variable. However, as variables need to be single values, I would need to simulate an array. The trick is to create the array as a comma separated list of values (string) and assign this to the variable as follows
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 result stored in #myvar is
5,6,7
Next, the FIND_IN_SET selector is used to select from the simulated array
SELECT * FROM mytable WHERE FIND_IN_SET(id,#myvar);
The combined final result is as follows:
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);
I am aware that this is a very specific case. However it can be modified to suit just about any other case where a variable needs to store an array of values.
I hope that this helps.
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 ;
Maybe create a temporary memory table with columns (key, value) if you want associative arrays. Having a memory table is the closest thing to having arrays in mysql
Here’s how I did it.
First, I created a function that checks whether a Long/Integer/whatever value is in a list of values separated by commas:
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;
So now you can search for an ID in a comma-separated list of IDs, like this:
select `is_id_in_ids`('1001,1002,1003',1002);
And you can use this function inside a WHERE clause, like this:
SELECT * FROM table1 WHERE `is_id_in_ids`('1001,1002,1003',table1_id);
This was the only way I found to pass an "array" parameter to a PROCEDURE.
I'm surprised none of the answers mention ELT/FIELD.
ELT/FIELD works very similar to an array especially if you have static data.
FIND_IN_SET also works similar but doesn't have a built in complementary
function but it's easy enough to write one.
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)
Is an array variable really necessary?
I ask because I originally landed here wanting to add an array as a MySQL table variable. I was relatively new to database design and trying to think of how I'd do it in a typical programming language fashion.
But databases are different. I thought I wanted an array as a variable, but it turns out that's just not a common MySQL database practice.
Standard Practice
The alternative solution to arrays is to add an additional table, and then reference your original table with a foreign key.
As an example, let's imagine an application that keeps track of all the items every person in a household wants to buy at the store.
The commands for creating the table I originally envisioned would have looked something like this:
#doesn't work
CREATE TABLE Person(
name VARCHAR(50) PRIMARY KEY
buy_list ARRAY
);
I think I envisioned buy_list to be a comma-separated string of items or something like that.
But MySQL doesn't have an array type field, so I really needed something like this:
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)
);
Here we define a constraint named fk_person. It says that the 'person' field in BuyList is a foreign key. In other words, it's a primary key in another table, specifically the 'name' field in the Person table, which is what REFERENCES denotes.
We also defined the combination of person and item to be the primary key, but technically that's not necessary.
Finally, if you want to get all the items on a person's list, you can run this query:
SELECT item FROM BuyList WHERE person='John';
This gives you all the items on John's list. No arrays necessary!
This is my solution to use a variable containing a list of elements.
You can use it in simple queries (no need to use store procedures or create tables).
I found somewhere else on the site the trick to use the JSON_TABLE function (it works in mysql 8, I dunno of it works in other versions).
set #x = '1,2,3,4' ;
select c.NAME
from colors c
where
c.COD in (
select *
from json_table(
concat('[',#x,']'),
'$[*]' columns (id int path '$') ) t ) ;
Also, you may need to manage the case of one or more variables set to empty_string.
In this case I added another trick (the query does not return error even if x, y, or both x and y are empty strings):
set #x = '' ;
set #y = 'yellow' ;
select c.NAME
from colors
where
if(#y = '', 1 = 1, c.NAME = #y)
and if(#x = '', 1, c.COD) in (
select *
from json_table(
concat('[',if(#x = '', 1, #x),']'),
'$[*]' columns (id int path '$') ) t) ;
This works fine for list of values:
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;
Both versions using sets didn't work for me (tested with MySQL 5.5). The function ELT() returns the whole set. Considering the WHILE statement is only avaible in PROCEDURE context i added it to my solution:
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__;
To be honest, i don't think this is a good practice. Even if its realy necessary, this is barely readable and quite slow.
Isn't the point of arrays to be efficient? If you're just iterating through values, I think a cursor on a temporary (or permanent) table makes more sense than seeking commas, no? Also cleaner. Lookup "mysql DECLARE CURSOR".
For random access a temporary table with numerically indexed primary key. Unfortunately the fastest access you'll get is a hash table, not true random access.
Another way to see the same problem.
Hope helpfull
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,');
If we have one table like that
mysql> select * from user_mail;
+------------+-------+
| email | user |
+------------+-------+-
| email1#gmail | 1 |
| email2#gmail | 2 |
+------------+-------+--------+------------+
and the array table:
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 |
We can select the rows of the second table as one array with CONCAT function:
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 |
+------------+-------+--------+------------+-------------+
In MYSQL version after 5.7.x, you can use JSON type to store an array. You can get value of an array by a key via MYSQL.
Inspired by the function ELT(index number, string1, string2, string3,…),I think the following example works as an array example:
set #i := 1;
while #i <= 3
do
insert into table(val) values (ELT(#i ,'val1','val2','val3'...));
set #i = #i + 1;
end while;
Hope it help.
Here is an example for MySQL for looping through a comma delimited string.
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;
this uses the get_from_delimiter_split_string function defined here: https://stackoverflow.com/a/59666211/3068233
I Think I can improve on this answer. Try this:
The parameter 'Pranks' is a 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;
This method makes the searched string of CSV values progressively shorter with each iteration of the loop, which I believe would be better for optimization.
I would try something like this for multiple collections. I'm a MySQL beginner. Sorry about the function names, couldn't decide on what names would be best.
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');
Rather than Saving data as a array or in one row only you should be making diffrent rows for every value received. This will make it much simpler to understand rather than putting all together.
Have you tried using PHP's serialize()?
That allows you to store the contents of a variable's array in a string PHP understands and is safe for the database (assuming you've escaped it first).
$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());
You can also do the exact same without a numbered array
$array2 = array(
'something' => 'something else'
);
or
$array3 = array(
'somethingNew'
);