mysql + all numbers from one field to Sum - mysql

Is it possible to sum the digits in a string and sort by that?
Example values: 19, 21
19 Should be transformed to 10. Explanation: 1+9=10
21 Should be transformed to 3. Explanation: 2+1= 3
After calculating these results, the table needs to be sorted by the resulting values (using SORT BY).
Originally, I have those values stored as JSON array, so it's ["1","9"] and ["2","1"], and in order to parse the JSON I'm using replace as follows:
REPLACE(REPLACE(REPLACE(item_qty, '["', ''), '"]', ''), '","', '')

How about trying something like:
SELECT (
SUBSTRING('["1","9"]', 3, 3) +
SUBSTRING('["1","9"]', 7, 7)
) AS sumOfDigits;
And then if the value ["1","9"] is stored in a column named json and the table is named table you van do:
SELECT * FROM (
SELECT table.*, (
SUBSTRING('json', 3, 3) +
SUBSTRING('json', 7, 7)
) AS sumOfDigits
FROM table
) tmp
ORDER BY sumOfDigits;

I would define a function to do the sum, as follow:
DELIMITER //
CREATE FUNCTION add_digits
(
number INTEGER
) RETURNS INTEGER
BEGIN
DECLARE my_sum INTEGER;
SET my_sum = 0;
SET number = ABS(number);
WHILE (number > 0) DO
SET my_sum = my_sum + (number MOD 10);
SET number = number DIV 10;
END WHILE;
RETURN my_sum;
END //
DELIMITER ;
You could also create a function that works directly on your json sting, parsing it for digits and adding their values.

Related

Mysql function to genarate custom ids

I need some help in creating a MySQL function
This function generates a user id for my user, Which generates 5 digits unique id starting from A0001, A0002, B0001, C0001, and so on but the problem is it reaches F9999 as per my function the following number should be G0000
But my requirement is can't go past letter F
We can't have a user id that is more than 5 'digits' and we can only use the letters A to F
Se I come with some Solution moving on to a range that is something like this: AA000, AA001, AA002.... and then AB000, AB001, AB002, AF999 BA000, etc.
This is my current function which I use to generate userid
DELIMITER $$
CREATE DEFINER=`root`#`localhost` FUNCTION `getNextID`() RETURNS varchar(10) CHARSET utf8
BEGIN
set #prefix := (select COALESCE(max(left(id, 1)), 'A') from users where left(id, 1) < 1);
set #highest := (select max(CAST(right(id, 4) AS UNSIGNED))+1 from users where left(id, 1) = #prefix);
if #highest > 9999 then
set #prefix := CHAR(ORD(#prefix)+1);
set #highest := 0;
end if;
RETURN concat( #prefix , LPAD( #highest, 4, 0 ) );
END$$
DELIMITER ;
Your ID can be thought of a hexadecimal number consisting of letters only, followed by a decimal number. Each hexadecimal digit starts a new series of decimal numbers, because the ID is of fixed length 5.
The first subproblem is to find the maximum ID, because it should be assumed that F9998 < F9999 < AA000 < AA001. We can calculate H*10000 + D with H being the hexadecimal part and D the decimal part of the ID to get the right order.
SELECT id
FROM (
SELECT 'AB999' as id UNION
SELECT 'AA000' UNION
SELECT 'F9999' UNION
SELECT 'AAA00' UNION
SELECT 'FFFF9' UNION
SELECT 'FFFF8' UNION
SELECT 'FFFD3') user
ORDER BY conv(regexp_substr(id, '^[A-F]*'), 16, 10) * 10000 + CAST(substring(id, length(regexp_substr(id, '^[A-F]*')) + 1) AS unsigned) DESC
LIMIT 1;
The second subproblem is to find the successor of a given ID. We calculate the decimal number like above but use the correct factor (10^n with n being the length of the decimal part) this time, then we add one to this number and convert it back to the hex/dec representation. In the hexadecimal part there may be 0s and 1s which have to be replaced by 'A'. Whenever the hex part gets longer, the decimal part consists of 0s only. That is, we can just return a substring of the desired length and strip trailing 0es:
DELIMITER //
CREATE FUNCTION nextId(id VARCHAR(5)) RETURNS VARCHAR(5) NO SQL
BEGIN
set #hexStr := regexp_substr(id, '^[A-F]*');
set #digits := length(id) - length(#hexStr);
set #decimalPart := CAST(right(id, #digits) AS UNSIGNED);
set #factor := pow(10, #digits);
set #hexPart := conv(#hexStr, 16, 10);
set #n := #hexPart * #factor + #decimalPart + 1; -- ID increased by 1
set #decimalPart := mod(#n, #factor);
set #hexStr := regexp_replace(conv(floor(#n / #factor), 10, 16), '[01]', 'A');
return substring(concat(#hexStr, lpad(#decimalPart, #digits, '0')), 1, length(id));
END;
//
DELIMITER ;
Using this function
SELECT id, nextId(id) next_id
FROM (
SELECT 'F9998' as id UNION
SELECT 'F9999' UNION
SELECT 'AA999' as id UNION
SELECT 'AB000' UNION
SELECT 'AB999' UNION
SELECT 'AF999' UNION
SELECT 'FF999' UNION
SELECT 'AAA00') user;
results in
id
next_id
F9998
F9999
F9999
AA000
AA999
AB000
AB000
AB001
AB999
AC000
AF999
BA000
FF999
AAA00
AAA00
AAA01
Here's a fiddle

MYSQL: Validate Input Values in Specific Format within a FUNCTION

i have one question with regard to MYSQL. I want to create a function that is able to check whether an Input is given in a specific format.
The output should be in the following shape:
***x x (a) n (n) (n) (n)
with :
x = letters and numbers
n = numbers
a = letters
brackets = optional Values***
my code is written below this.
CREATE FUNCTION validate_of_number(testnumber VARCHAR(7))
RETURNS INT
DETERMINISTIC
RETURN
CASE
WHEN
(SELECT * FROM flightexecution WHERE FlightNo REGEXP
'^[[:alnum:]+[:alnum:]] + [[:alpha:]|''] + [:digit:] +
[[:digit:]|''] + [[:digit:]|''] + [[:digit:]|'']') > 0
Then 1
Else 0
END;`
However, it does not work and i don´t know why. The Output is just a 'OK' without any further information.
I'm assuming based on your description of valid values and the context of your question that the values you are trying to validate look something like CX727 or QF1566 or BA1 etc (i.e. IATA flight designator codes). In that case, this function will give you the results you want:
CREATE FUNCTION validate_of_number(testnumber VARCHAR(7))
RETURNS INT
DETERMINISTIC
RETURN testnumber REGEXP '^[[:alnum:]]{2}[[:alpha:]]?[[:digit:]]{1,4}$';
Examples:
SELECT validate_of_number('A1B4352')
, validate_of_number('QF12')
, validate_of_number('CX727')
, validate_of_number('AB14352')
, validate_of_number('BA1')
, validate_of_number('1C42')
Output
1, 1, 1, 0, 1, 1
Demo on dbfiddle
In terms of using it with your table you might use a query like
SELECT * FROM flightexecution WHERE validate_of_number(FlightNo)

MySql search integer range from number with dash

I have table in that I have one field with dash value. Like...
I need to search this with between condition.
For example if I have one value 25 then I need to search the records which include the value 25 like 20-31. In above image there are 6 records which include 25 value. So it should return 6 records.
Please help me in this query ? What would be the query for that ?
You can use MySQL's substring_index() function to easily get the data before and after the dash:
select substring_index(yourcolumn,'-',1) as `lower`, substring_index(yourcolumn,'-',-1) as `upper`
from yourtable
This way you can return the records where a certain value falls between the range:
select * from yourtable
where 25 between substring_index(yourcolumn,'-',1) + 0 and substring_index(yourcolumn,'-',-1) + 0
The + 0 forces MySQL to convert the result of substring_index() to a numeric value before the comparison.
You can use the following solution using SUBSTRING_INDEX:
SELECT *
FROM table_name
WHERE 25 >= CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 1), '-', -1), UNSIGNED INTEGER)
AND 25 <= CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 2), '-', -1), UNSIGNED INTEGER)
-- or
SELECT *
FROM table_name
WHERE 25 BETWEEN CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 1), '-', -1), UNSIGNED INTEGER)
AND CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 2), '-', -1), UNSIGNED INTEGER)
demo: http://sqlfiddle.com/#!9/4ac7b3/3/0
I recommend you to change your table design. I would split the column using the VARCHAR datatype to two columns using the INTEGER datatype. You can add two new columns with the the following ALTER TABLE commands:
ALTER TABLE table_name ADD colNameA INT;
ALTER TABLE table_name ADD colNameB INT;
To split the values of you current column and update the values to the new columns you can use the following UPDATE command:
UPDATE table_name SET
colNameA = CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 1), '-', -1), UNSIGNED INTEGER),
colNameB = CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 2), '-', -1), UNSIGNED INTEGER)
At the end you can remove the VARCHAR column using this ALTER TABLE command:
ALTER TABLE table_name DROP COLUMN col_name
Now you can use the following (simple) query to get the expected results:
SELECT *
FROM table_name
WHERE 25 >= colNameA AND 25 <= colNameB
-- or
SELECT *
FROM table_name
WHERE 25 BETWEEN colNameA AND colNameB
If you want to get values beween 35 and 39, you can use below query,
SELECT
*
FROM
yourtable
WHERE
35 && 39
BETWEEN SUBSTRING_INDEX(tablecolumn, '-', 1) + 0 AND
SUBSTRING_INDEX(tablecolumn, '-', - 1) + 0
I don't know how it possible with MySQL.
But using php it possible to check with range.
For e.g.
// First of all get all record from database.
$search = 10; // Your searching value.
// Loop all rows.
while($rows = mysqli_fetch_array($r)){
$explode = explode("-",$rows['dash']); // For get from-to value.
$range = isset($explode[0])&&isset($explode[1])?range($explode[0],($explode[1]-1)):array(); // For get range.
if(in_array($search,$range)){ // For check searching value is exist or not !
echo "Yes ! I get into ".$rows['dash']; // Do stuff.
}
}
Note: If 10-15 then it will check with 10,11,12,13,14.
According to me if you dont want to change the table structure then,
Just fetch the records as per your other condition, Then from that data check your amount between that field using foreach loop and explode. like
If you have $data as all data
foreach($data as $value){
$new_val=explode(',',$value['new_field']);
if(25 >= $new_val[0] && 25 <= $new_val[1]){
// here create new array
}
}

Does Oracle have any equivalent function for mysql "FIELD"

This is my MySQL query. How can I run this query in Oracle? Right now it's not working.
SELECT * FROM mytable WHERE id IN (1,2,3,4) ORDER BY FIELD(id,3,2,1,4);
Here is a stupid solution: (:-D)
SELECT * FROM mytable WHERE id IN (1,2,3,4)
ORDER BY CASE id WHEN 3 THEN 1
WHEN 2 THEN 2
WHEN 1 THEN 3
WHEN 4 THEN 4 END;
Or use DECODE function:
SELECT * FROM mytable WHERE id IN (1,2,3,4)
ORDER BY DECODE(id, 3, 1, 2, 2, 1, 3, 4, 4, 0)
Oracle does not have a FIELD function but you can create your own instead
create TYPE T_VAR IS TABLE OF varchar2(4000);
/
create or replace function FIELD(p_val varchar2, p_var t_var) return number is
begin
for i in 1..p_var.count
loop
if p_val = p_var(i) then
return i;
end if;
end loop;
return p_var.count + 1;
end FIELD;
/
Query
SELECT t.*
FROM mytable t
WHERE id IN (1, 2, 3, 4)
order by FIELD(id,T_VAR(3,2,1,4))
NOTE: You should create one more function FIELD with this signature FIELD (p_val number, p_var t_var) for explicit data type conversation. Function before is universal but can be cause of some bizarre effects.

MySQL truncate text with ellipsis

Suppose I have a MySQL table of one column: "Message". It is of type TEXT.
I now want to query all rows, but the text can be large (not extremely large but large) and I only want to get a summary of them. For example the result can be populated into a list.
Is there a way to trim the text to a specific length (say, 10 characters), and add ellipsis if the text is trimmed?
For example:
Message
-----------
12345678901234
1234567890
12345
12345678901
Query result:
1234567...
1234567890
12345
1234567...
Thanks!
select case when length(message) > 7
then concat(substring(message, 1, 7), '...')
else message end as adapted_message
from ...
to test/confirm:
SELECT CASE WHEN LENGTH('1234567890') > 7
THEN CONCAT(SUBSTRING('1234567890', 1, 7), '...')
ELSE '1234567890' END AS adapted_message
UNION
SELECT CASE WHEN LENGTH('12345') > 7
THEN CONCAT(SUBSTRING('12345', 1, 7), '...')
ELSE '12345' END AS adapted_message
Here's a simple one line solution:
IF(CHAR_LENGTH(message) > 10, CONCAT(LEFT(message, 7),"..."), message)
or...
SELECT CONCAT(LEFT(message, 7), IF(LENGTH(message)>7, "…", ""))
FROM table
You can declare a new ELLIPSIS function in order to make your query readable:
DELIMITER //
CREATE FUNCTION ELLIPSIS ( str TEXT, max_length INT )
RETURNS TEXT
BEGIN
DECLARE str_out TEXT;
IF LENGTH(str) <= max_length THEN
SET str_out = str;
ELSE
SET str_out = CONCAT(SUBSTR(str, 1, max_length-3), '...');
END IF;
RETURN str_out;
END; //
DELIMITER ;
Then you simply do:
SELECT ELLIPSIS(Message, 10);
Have a look at the MySQL string functions, documented here. You should be able to use some combination of substring and concat to achieve your desired behaviour.
My approach:
Let x be the maximum number of characters to display (therefore x + 3 dots will be the longest string displayed)
You always want LEFT(field,x)
If LENGTH(field) > x + 3, append 3 dots
Otherwise if LENGTH(field) > x, append the remainder of field
SELECT CONCAT(
LEFT(field,x),
IF(LENGTH(field) > x+3,
'...',
IF(LENGTH(field) > x,
MID(field,x+1,LENGTH(field)),
''
)
)
) FROM table