MySQL failing on LEFT() with String 8863 characters long? - mysql

Yet another fun and unexplained issue with MySQL. Code works perfectly fine with all other shorter strings (and has been for months), but when I try to following code on a String that's 8863 in length (designed to simply remove a comma as the last character), it just does nothing. No error or anything. Length is 8863 both before and after the execution (and note the RIGHT check works fine so the LEFT executes, it just fails to remove the last comma). As mentioned, ONLY happens with a very long string.
Anyone know what crazy limitations in MySQL I might be dealing with?
DECLARE var_sql_insert_1 text;
IF (RIGHT(var_sql_insert_1, 1) = ',') THEN
SET var_sql_insert_1 = LEFT(var_sql_insert_1, LENGTH(var_sql_insert_1) - 1);
END IF;

So the issue is I was using LENGTH which was returning the length in BYTES vs. CHAR_LENGTH which returns the length in characters. Sadly, with all the other languages I've used, the default LENGTH value was character and they BYTE_LENGTH was specifically designed to be byte. For MySQL it appears the reverse is true. Doesn't make much sense for a system that's mainly used to store and manipulate TEXT rather than byte data...

Since MySQl 8 where introduced function REGEXP_REPLACE you can use next solution:
SET var_sql_insert_1 = REGEXP_REPLACE(var_sql_insert_1, ',$', '');
The pattern ',$' mean last comma before end of line $
Look the example

Related

How to remove string that is no longer needed in MySQL database?

This seemed like it should be very simple to do yet I've not been able to find an answer after weeks of looking.
I'm trying to remove strings that are no longer needed. Regex_replace sounds perfect but is not available in MySQL.
In MySQL how would I accomplish changing this:
[quote=ABC;xxxxxx]
to this:
[quote=ABC]
The issues are:
- this can appear anywhere in a text blob
- the xxxxxx can only be numeric but may be 6, 7 or 8 characters long
- not adding/removing any rows, just rewriting the contents of one column on one row at a time.
Thanks.
I don't think you really need REGEX_Replace (though it would make things easier of course).
Assuming that the example you presented is a real reflection of what you have:
Your starting point is with the string [quote=<something>;, meaning that you can start searching for [quote=,
Once you found it, you need to search for ; and after that for ],
Once you found them both, you know what to extract when where to start for the next search (if the pattern you mentioned can appear more than once within a singe blob.
Did I get you correctly?
EDIT
This paradigm is aimed to convert all instances of [quote=ABC;xxxxxx] to [quote=ABC] under the following assumptions:
The pattern can appear any number of times within the input string,
The length of xxxxxx is not fixed,
The resulting string (after removing all the appearances of ;xxxxxx) should replace the value in the table,
Performance is not an issue since either this is going to be a one-time job (through the whole table) or it will run every time on a single string (e.g. before INSERTing a new record).
Some MySQL functions that will be used:
INSTR: Searches within a string for the first appearance of a sub-string and returns the position (offset) where the sub-string was found,
SUBSTR: Returns a substring from a string (several ways to use it),
CONCAT: Concatenates two or more strings.
The guidelines presented here apply for the manipulation of a single INPUT string. If this needs to be used over, say, a whole table, simply get the strings into a CURSOR and loop.
Here are the steps:
Declare five INT local variables to serve as indices and total input string length, say L_Start, L_UpTo, l_Total_Length, l_temp1 and l_temp 2, setting the initial value for l_Start = 1 and l_Total_Length = LENGTH(INPUT_String),
Declare a string variable into which you will copy the "cleaned" result and initiate it as '', say l_Output_str; also declare a temporary string to hold the value of 'ABD', say l_Quote,
Start a infinite loop (you will set the exit condition within it; see below),
Exit loop if l_Start >= l_Total_Length (here is one of the two exit points from the loop),
Find the first location of '[quote=' within the input string starting from L_Start,
If the returned value is 0 (i.e. substring not found), concatenate the current contents of l_Output_str with whatever remains if the input string from position L_start (e.g. SET l_Output_str = CONCAT(l_Output_str,SUBSTR(INPUT_String,L_Start) ;) and exit loop (second exit position),
Search the input string for the ; symbol starting from L_start + 7 (i.e. the length of [quote=) and save the value in l_temp_1,
Search the input string for the ] symbol starting from L_start + 7 + l_temp2 and save the value in l_temp_2,
Add the found result to output string as SET l_Output_str = CONCAT(l_Output_str,'[quote=',SUBSTR(INPUT_String,L_Start + 7, l_temp_2 - l_temp_1),']') ;,
Set L_Start = L_Start + 7 + l_temp_2 + 1 ;
End of loop.
Notes:
As I neither made the code nor tested it, it is possible that I'm not setting indices correctly; you will need to perform detailed tests to make get it working as needed;
The above IS the method I suggested;
If the input string is very long (many MBs), you might observe poor performance (i.e. it might take few seconds to complete) because of the concatenations. There are some steps that can be taken to improve performance, but let's have this working first and then, if needed, tackle the performance issues.
Hope that the above is clear and comprehensive.

Convert/encode string to numbers

I'm looking around to encode/cast/convert a string into numbers within a query. Like ASCII() but it only returns the left-most character to its relative code. Is there any function or method available on this topic? -which is actually decode-able
JUST For example:
METHOD("test-string") # Outputs: 25478596325417
This will work for strings up to 8 characters long.
To encode:
SELECT CONV(HEX(string), 16, 10);
To decode:
SELECT UNHEX(CONV(number, 10, 16));
MySQL supports integers up to 64 bit long, and this method uses 8 bits per character. Therefore using this method you can store up to 64 / 8 = 8 characters in an integer.
If hexadecimal is good enough for your application, then then function hex() does what you want. For instance, you can try:
select hex('abc'), hex('abcd')
This will work on arbitrary strings. If this doesn't quite work, then perhaps there is a way to convert the hex representation to something appropriate.
By the way, unhex() will return the original string.
You could use
COMPRESS('ABC)
To get a binary string that is not the string. It can compress an arbitrary size. But it is not clear what you are going to do with the number -- or how you need to store it.
Try this one.
SELECT CAST(HEX(your_string) AS DECIMAL);
I admit, I didn't test it, but it should work.
EDIT:
Some other databases (e.g. Oracle, DB2, PostgreSQL) have the function TRANSLATE() for it. Unfortunately MySQL does not support it. And as far as I know no replacement for this function in MySQL exists currently. So using nested REPLACE() is probably the only option currently.

MySQL integer comparison ignores trailing alpha characters

So lets just say I have a table with just an ID is an int. I have discovered that running:
SELECT *
FROM table
WHERE ID = '32anystring';
Returns the row where id = 32. Clearly 32 != '32anystring'.
This seems very strange. Why does it do this? Can it be turned off? What is the best workaround?
It is common behavior in most programming languages to interpret leading numerals as a number when converting a string to a number.
There are a couple of ways to handle this:
Use prepared statements, and define the placeholder where you are putting the value to be of a numeric type. This will prevent strings from being put in there at all.
Check at a higher layer of the application to validate input and make sure it is numeric.
Use the BINARY keyword in mysql (I'm just guessing that this would work, have never actually tried it as I've always just implemented a proper validation system before running a query) -
SELECT *
FROM table
WHERE BINARY ID = '32anystring';
You need to read this
http://dev.mysql.com/doc/refman/5.1/en/type-conversion.html
When you work on, or compare two different types, one of them will be converted to the other.
MySQL conversion of string->number (you can do '1.23def' * 2 => 2.46) parses as much as possible of the string as long as it is still a valid number. Where the first letter cannot be part of a number, the result becomes 0

mumps query related to %%

What is the meaning of I $E(R%%,I%%)>1 ? and why using %%?
Actually, if you are talking about Standard MUMPS (not any particular implementation)
the R%% is illegal syntax. I have seen the non-standard use of % in extensions to MUMPS, such as EsiObjects or InterSystems Cache Object Script, but the use in the question above is actually nonsense in standard MUMPS.
There is no particular significance to %%. Its just part of the variable name and I still don't understand MUMPS community obsession with using % in variable names and making them more obscure.
so the statement means IF $EXTRACT(R%%,I%%)>1 i.e if the extracted value from the string R%% at position I%% is greater than 1, do some more obscure stuff.
$EXTRACT(string,from) extracts a
single character in the position
specified by from. The from value can
be an integer count from the beginning
of the string, an asterisk specifying
the last character of the string, or
an asterisk with a negative integer
specifying a count backwards from the
end of the string.
Link to documentation: http://docs.intersystems.com/cache20102/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fextract

How to remove digits from the end of the string using SQL

Please, could you answer my question.
How to remove digits from the end of the string using SQL?
For example, the string '2Ga4la2009' must be converted to 2Ga4la. The problem is that we can't trim them because we don't know how many digits are in the end of the string.
Best regards, Galina.
This seems to work:
select left( concat('2Ga4la2009','1'), length(concat('2Ga4la2009','1')) - length(convert(convert(reverse(concat('2Ga4la2009','1')),unsigned),char)))
The concat('myvalue', '1') is to protect against numbers that end in 0s.
The reverse flips it around so the number is at the front.
The inner convert changes the reversed string to a number, dropping the trailing chars.
The outer convert turns the numeric part back to characters, so you can get the length.
Now you know the length of the numeric portion, and you can determine the number of characters of the original value to chop off with the "left()" function.
Ugly, but it works. :-)
Take a look at this: http://www.mysqludf.org/lib_mysqludf_preg/
And if you for some reason can't use UDF, and don't want to do it on the db client side, you can always do the following:
Find the position of the first letter from the end (e.g. the minimum of the 25 LOCATEs on the string's reverse)
Do LEFT(#string, #string_length - #result_of_step_1)
You don't have to do any special handling in case there aren't any digits at the end of the string because in this case LOCATE returns 0.
Cheers