I am trying to create a an encryption in MySQL.
Lets say there is a string of characters.
"I can run for as many".
I want to replace each letter with its fourth letter.
For example,
'a' replaced with 'e'
'b' replaced with 'f'
and so on.
The Final output of the above would look something like this.
"M gen vyr jsr ew qerc"
The best I could come up is the below.
Since it is a nested function, it is not giving me the right result.
The below function replaces 'a' with 'e' and then again replaces 'e' with 'i'
until it reaches the end.
select messagetext,
replace(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(messagetext,'a','e'),
'b','f'),'c','g'),'d','h'),'e','i'),'f','j'),'g','k'),
'h','l'),'i','m'),'j','n'),'k','o'),'l','p'),'m','q'),
'n','r'),'o','s'),'p','t'),'q','u'),'r','v'),'s','w'),
't','x'),'u','y'),'v','z'),'w','a'),'x','b'),'y','c'),
'z','d')
from chat;
Any help would be much appreciated.
Reached partial solution, now stuck.
Putting it here so that others can work on this.
Query:
SELECT UNHEX(HEX(val) + REPEAT('04', LENGTH(val))) AS rot4 FROM caeser;
+--------+
| rot4 |
+--------+
| efghip |
| aq?? | <-- Need to rotate / mod hex value for this. (Stuck here)
+--------+
Table create queries:
CREATE TABLE caeser (val VARCHAR(255));
INSERT INTO caeser ('abcdef');
INSERT INTO caeser VALUES ('uvwxyz');
PS: will convert to community wiki, if others also contribute.
Related
I am trying to get the integer value between two specific strings but I am stacked a little bit.
Example full string:
"The real ABC4_ string is probably company secret."
I need to get the "4" between "ABC" and "_". First I've came up with following script:
select substring_index(substring_index('The real ABC4_ string is probably company secret.', 'ABC', -1),'_', 1);
It gives me 4, perfect! But the problem is if ABC occurs more than one time in the string it fails. I can't simply increase the counter also since I don't know how many times it will be in the future. I have to get first occurrence of that regex: ABC[DIGIT]_
I've seen REGEXP_SUBSTR function but since we use older version of MySQL than 8.0 I can't use it also.
Any suggestions?
Thanks!
Without using Regex, here is an approach using LOCATE(), and other string functions:
SET #input_string = 'The real ABC4_ string is probably company secret.';
SELECT TRIM(LEADING 'ABC'
FROM SUBSTRING_INDEX(
SUBSTR(#input_string FROM
LOCATE('ABC', #input_string)
)
,'_', 1
)
) AS number_extracted;
| number_extracted |
| ---------------- |
| 4 |
View on DB Fiddle
Another way of (ab)using the LOCATE() function:
select substr('The real ABC4_ string is probably company secret.',
locate('ABC', 'The real ABC4_ string is probably company secret.') + 3,
locate('_','The real ABC4_ string is probably company secret.') -
locate('ABC', 'The real ABC4_ string is probably company secret.') - 3) AS num;
I have a SQL Table in that i use BETWEEN Operater.
The BETWEEN Operater selects values within range. The values can be numbers, text , dates.
stu_id name city pin
1 Raj Ranchi 123456
2 sonu Delhi 652345
3 ANU KOLKATA 879845
4 K.K's Company Delhi 345546
5 J.K's Company Delhi 123456
I have a query like this:-
SELECT * FROM student WHERE stu_id BETWEEN 2 AND 4 //including 2 & 4
SELECT * FROM `student` WHERE name between 'A' and 'K' //including A & not K
Here My Question is why not including K.
but I want K also in searches.
Don't use between -- until you really understand it. That is just general advice. BETWEEN is inclusive, so your second query is equivalent to:
WHERE name >= 'A' AND
name <= 'K'
Because of the equality, 'K' is included in the result set. However, names longer than one character and starting with 'K' are not -- "Ka" for instance.
Instead, be explicit:
WHERE name >= 'A' AND
name < 'L'
Of course, BETWEEN can be useful. However, it is useful for discrete values, such as integers. It is a bit dangerous with numbers with decimals, strings, and date/time values. That is why I encourage you to express the logic as inequalities.
In supplement to gordon's answer, one way to get what you're expecting is to turn your name into a discrete set of values:
SELECT * FROM `student` WHERE LEFT(name, 1) between 'A' and 'K'
You need to appreciate that K.K's Company is alphabetically AFTER the letter K on its own so it is not BETWEEN, in the same way that 4.1 is not BETWEEN 2 and 4
By stripping it down to just a single character from the start of the string it will work like you expect, but take cautionary note, you should always avoid running functions on values in tables, because if you had a million names, thats a million strings that mysql has to strip out to just the first letter and it might no longer be able to use an index on name, battering the performance.
Instead, you could :
SELECT * FROM `student` WHERE name >= 'A' and name < 'L'
which is more likely to permit the use of an index as you aren't manipulating the stored values before comparing them
This works because it asks for everything up to but not including L.. Which includes all of your names starting with K, even kzzzzzzzz. Numerically it is equivalent to saying number >= 2 and number < 5 which gives you all the numbers starting with 2, 3 or 4 (like the 4.1 from before) but not the 5
Remember that BETWEEN is inclusive at both ends. Always revert to a pattern of a >= b and a < c, a >= c and a < d when you want to specify ranges that capture all possible values
Compare in lexicographical order, 'K.K's Company' > 'K'
We should convert the string to integer. You can try that mysql script with CAST and SUBSTRING. I've updated your script here. It will include the last record as well.
SELECT * FROM student WHERE name CAST(SUBSTRING(username FROM 1) AS UNSIGNED)
BETWEEN 'A' AND 'K';
The script will work. Hope it will helps to you.
Here I've attached my test sample.
given below is my table structure
Mobile_Number_Start | Mobile_Number_End
005555 | 006565
016565 | 017575
018585 | 019595
Now I have to search record depending on if user enter mobile number start or end. He can also enter number in either of column but not complete number
Suppose if user enters 01 the record table will show output as
Mobile_Number_Start | Mobile_Number_End
016565 | 017575
018585 | 019595
So for this I can't create a query that works
Here is what my query looks like
Select * from table_name where mobile_number_start is less than value entered in start and mobile_number_end is greater than value in mobilenumberend
I have carried out this operation using findall function of repository by building a specification builder class and passin the specification in
findAll(specification)
I need help in writing query for when user enters a part of mobile number but not complete number
you can use the LIKE operator on your query
SELECT *
FROM table_name
WHERE mobile_number_start LIKE '01%' and mobile_number_end LIKE '%01'
Try this one.
SELECT *
FROM table_name
WHERE CAST(mobile_number_start as CHAR) LIKE '01%'
and CAST(mobile_number_end as CHAR) LIKE '%01'
You can use like operator for comparison,
SELECT * FROM table WHERE start_number LIKE '1%' and end_number LIKE '%1';
I have a table with some words that come from medieval books and have some accented letters that doesn't exists anymore in modern latin1 alphabet. I can represent these letters easily with UTF-8 combining characters. For example, to create a "J" with a tilde, I use the UTF-8 sequence \u004A+\u0303 and the J becomes accented with a tilde.
The table uses utf8 encoding and the field collation is utf8_unicode_ci.
My problem is the following: If I try to select the entire string, I receive the correct answer. If I try to select using 'LIKE', I receive the wrong answer.
For example:
mysql> select word, hex(word) from oldword where word = 'hua';
+--------+--------------+
| word | hex(word) |
+--------+--------------+
| hũa | 6875CC8361 |
| huã | 6875C3A3 |
| hua | 687561 |
| hũã | 6875CC83C3A3 |
+--------+--------------+
4 rows in set (0,04 sec)
mysql> select word, hex(word) from oldword where word like 'hua';
+-------+------------+
| word | hex(word) |
+-------+------------+
| huã | 6875C3A3 |
| hua | 687561 |
+-------+------------+
2 rows in set (0,04 sec)
I don't want to search only the entire word. I want to search words that start with some substring. Eventually the searched word is the entire word.
How could I select the partial string using like and match all the strings?
I tried to create a custom collation using this information, but the server became unstable and only after a lot of trials and errors I was able to revert to the utf8_unicode_ci collation again and the server returned to normal condition.
EDIT: There's a problem with this site and some characters don't display correctly. Please see the results on these pastebins:
http://pastebin.com/mckJTLFX
http://pastebin.com/WP87QvgB
After seeing Marcus Adams' answer I realized that the REPLACE function could be the solution for this problem, although he didn't mentioned this function.
As I have only two different combining characters (acute and tilde), combined with other ASCII characters, for example j with tilde, j with acute, m with tilde, s with tilde, and so on. I just have to replace these two characters when using LIKE.
After searching the manual, I learned about the UNHEX function that helped me to properly represent the combining characters alone in the query to remove them.
The combining tilde is represented by CC83 in HEX code and the acute is represented by CC81 in HEX.
So, the query that solves my problem is this one.
SELECT word, REPLACE(REPLACE(word, UNHEX("CC83"), ""), UNHEX("CC81"), "")
FROM oldword WHERE REPLACE(REPLACE(word, UNHEX("CC83"), ""), UNHEX("CC81"), "")
LIKE 'hua%';`
The problem is that LIKE performs the comparison character-by-character and when using the "combining tilda", it literally is two characters, though it displays as one (assuming your client supports displaying it as such).
There will never be a case where comparing e.g. hu~a to hua character-by-character will match because it's comparing ~ with a for the third character.
Collations (and coercions) work in your favor and handle such things when comparing the string as a whole, but not when comparing character-by-character.
Even if you considered using SUBSTRING() as a hack instead of using LIKE with a wildcard % to perform a prefix search, consider the following:
SELECT SUBSTRING('hũa', 1, 3) = 'hua'
-> 0
SELECT SUBSTRING('hũa', 1, 4) = 'hua'
-> 1
You kind of have to know the length you're going for or brute force it like this:
SELECT * FROM oldword
WHERE SUBSTRING(word, 1, 3) = 'hua'
OR SUBSTRING(word, 1, 4) = 'hua'
OR SUBSTRING(word, 1, 5) = 'hua'
OR SUBSTRING(word, 1, 6) = 'hua'
According to this:
ũ collates equal to plain U in all utf8 collations on 5.6.
j́ collates equal to plain J in most collations; exceptions:
utf8_general*ci because it is actually j plus an accent. And the "general" collations only look at one character (as distinguished from byte) at a time. Most collations take into consideration multiple characters, such as ch or ll in Spanish or ss in German.
utf8_roman_ci, which is quite an oddball. j́=i=j
(LIKE does not exactly follow the regular rules of collation. I am not versed on the details, but I think that J is represented as 2 characters causes it to work differently in LIKE than in WHERE or ORDER BY. Furthermore, I don't know whether REPLACE() collates like LIKE or the other places.)
You can use the % symbol like a wildcard character. For example this:
SELECT word
FROM myTable
WHERE word LIKE 'hua%';
This will pull all records that start with hua and have 0+ characters following it. Here is an SQL Fiddle example.
Consider the situation i have a table name "test"
-------
content (varchar(30))
-------
1
abc
2
bcd
-------
if i use order by
Select * from test order by content asc
i could get result like
--------
content
--------
1
2
abc
bcd
---------
but is there any way i could get the following result using query
--------
content
--------
abc
bcd
1
2
---------
To get by the collation, you can do by testing the first character... it appears you want anything starting with a numeric to be after anything alhpa oriented... something like the ISNUMERIC() representation by Ted, but my quick check doesn't show such function in MySQL.. So an alternative... because numerics in ASCII list are less than "A" (char 65)
Select *
from test
order by
case when left( content, 1 ) < "A" then 2 else 1 end,
content
Although I've seen different CONVERT() calls, I don't have MySQL available to confirm. However, in addition to the above case/when, you can add a SECOND case/when and call some UDF() or other convert function on the "content" value. If the string starts as alpha, it should return a zero value so the first case/when will keep them to the top of the list, then since all are all non-convertible to numeric would have a value of zero... no impact on the sort, then finally the content itself which will keep in alpha order.
HOWEVER, if your second case/when / convert function call DOES return a numeric value, then it will be properly sorted within the numeric grouping segment... which will then supercede that of the content... However, if content was something like
100 smith rd and
100 main st
they will sort in the same "100" category numeric value, but then alphabetically by the content as
100 main st
100 smith rd
100
this will do it:
SELECT *
FROM test
ORDER BY CAST(field AS UNSIGNED), field ASC
select * from sometable order by content between '0' and '9', content
Not sure on MySql but on SQL Server you can do this...
SELECT * FROM test
ORDER BY IsNumeric(content), content
The order of results is defined by collation used, so if you can find the right collation then yes.
http://dev.mysql.com/doc/refman/5.0/en/charset-collate.html
//edit
This is tricky. I've done some research and it seems that no currently available collation can do that. However there's also possibility to add new collation to MySQL. Here's how.