Issues in inserting comma separated strings to table - oracle

I have following 3 parameters from stored procedure
P_Param1 = 12
P_Paramj2= 'val:15,val:16'
P_param3 = 'Name:check values,Name:bv,Name:cv'
I have a table and need to insert above details and final table looks like below
proID CatID CatName
12 15 check values
12 15 bv
12 15 cv
12 16 check values
12 16 bv
12 16 cv
I have written a query to split P_param3 as below and getting splitted values but stuck in generating loops to make a table like above.
SELECT
regexp_substr('Name:check values,Name:bv,Name:cv', '(Name:)?(.*?)(,Name:|$)', 1, level, NULL,
2) AS "CatName"
FROM
dual
CONNECT BY
level <= regexp_count('Name:check values,Name:bv,Name:cv', 'Name:');

Split the catIds into rows and split the catNames into rows and then CROSS JOIN them and insert.
You can do it with simple (fast) string functions using:
CREATE PROCEDURE insertCats(
p_proid IN table_name.proid%TYPE,
p_catids IN VARCHAR2,
p_catnames IN VARCHAR2
)
IS
c_catid_prefix CONSTANT VARCHAR2(10) := 'val:';
c_catid_length CONSTANT PLS_INTEGER := LENGTH(c_catid_prefix);
c_catname_prefix CONSTANT VARCHAR2(10) := 'Name:';
c_catname_length CONSTANT PLS_INTEGER := LENGTH(c_catname_prefix);
BEGIN
INSERT INTO table_name (proid, catid, catname)
WITH catid_bounds (catids, spos, epos) AS (
SELECT p_catids,
1 + c_catid_length,
INSTR(p_catids, ',', 1 + c_catid_length)
FROM DUAL
UNION ALL
SELECT catids,
epos + 1 + c_catid_length,
INSTR(catids, ',', epos + 1 + c_catid_length)
FROM catid_bounds
WHERE epos > 0
),
catids (catid) AS (
SELECT CASE epos
WHEN 0
THEN SUBSTR(catids, spos)
ELSE SUBSTR(catids, spos, epos - spos)
END
FROM catid_bounds
),
catname_bounds (catnames, spos, epos) AS (
SELECT p_catnames,
1 + c_catname_length,
INSTR(p_catnames, ',', 1 + c_catname_length)
FROM DUAL
UNION ALL
SELECT catnames,
epos + 1 + c_catname_length,
INSTR(catnames, ',', epos + 1 + c_catname_length)
FROM catname_bounds
WHERE epos > 0
),
catnames (catname) AS (
SELECT CASE epos
WHEN 0
THEN SUBSTR(catnames, spos)
ELSE SUBSTR(catnames, spos, epos - spos)
END
FROM catname_bounds
)
SELECT p_proid,
i.catid,
n.catname
FROM catids i CROSS JOIN catnames n;
END;
/
db<>fiddle here

Related

How to compare 2 columns and return the difference in oracle SQL

We have 2 columns in one table in oracle SQL as
Col1= "there is book on the table"
Col2= "there are flowers on the chair"
Now I need the result as differed data in the column3 as new column col3.
The col3 result should be
"are flowers chair".
How to achieve this in oracle SQL??
You can use:
WITH words ( rid, col, name, id, word ) AS (
SELECT rid,
CASE INSTR(col, ' ')
WHEN 0
THEN NULL
ELSE SUBSTR(col, INSTR(col, ' ') + 1)
END,
name,
1,
CASE INSTR(col, ' ')
WHEN 0
THEN col
ELSE SUBSTR(col, 1, INSTR(col, ' ') - 1)
END
FROM ( SELECT ROWID AS rid, col1, col2 FROM table_name )
UNPIVOT ( col FOR name IN (col1, col2) )
UNION ALL
SELECT rid,
CASE INSTR(col, ' ')
WHEN 0
THEN NULL
ELSE SUBSTR(col, INSTR(col, ' ') + 1)
END,
name,
id + 1,
CASE INSTR(col, ' ')
WHEN 0
THEN col
ELSE SUBSTR(col, 1, INSTR(col, ' ') - 1)
END
FROM words
WHERE col IS NOT NULL
),
paired_words ( rid, id1, id2 ) AS (
SELECT c1.rid,
c1.id AS id1,
c2.id AS id2
FROM ( SELECT rid, id, word FROM words WHERE name = 'COL1' ) c1
INNER JOIN
( SELECT rid, id, word FROM words WHERE name = 'COL2' ) c2
ON (c1.rid = c2.rid AND c1.word = c2.word)
),
max_path ( rid, path ) AS (
SELECT rid,
path
FROM (
SELECT rid,
SYS_CONNECT_BY_PATH(id2, ',') || ',' AS path,
ROW_NUMBER() OVER (PARTITION BY rid ORDER BY LEVEL DESC) AS rn
FROM paired_words
CONNECT BY PRIOR rid = rid
AND PRIOR id1 < id1
AND PRIOR id2 < id2
)
WHERE rn = 1
)
SELECT LISTAGG(word, ' ') WITHIN GROUP (ORDER BY id) AS missing
FROM words w
WHERE NOT EXISTS (
SELECT 1
FROM max_path mp
WHERE w.rid = mp.rid
AND mp.path LIKE '%,' || w.id || ',%'
)
AND w.name = 'COL2'
GROUP BY rid;
Which, for the sample data:
CREATE TABLE table_name ( col1, col2 ) AS
SELECT 'there is book on the table', 'there are flowers on the chair' FROM DUAL UNION ALL
SELECT 'there is book on the table', 'there is a book on the table' FROM DUAL UNION ALL
SELECT 'there is book on the table', 'there is book there is book on the table on the table' FROM DUAL
Outputs:
MISSING
are flowers chair
a
there is book on the table
db<>fiddle here
Here's one option (which follows what you asked). Read comments within code.
SQL> with test (id, col1, col2) as
2 (select 1, 'there is book on the table',
3 'there are flowers on the chair'
4 from dual
5 ),
6 -- split sentences into words (each in its own line)
7 sent1 as
8 (select id,
9 column_value cv,
10 regexp_substr(col1, '[^ ]+', 1, column_value) word
11 from test cross join
12 table(cast(multiset(select level from dual
13 connect by level <= regexp_count(col1, ' ') + 1
14 ) as sys.odcinumberlist))
15 ),
16 sent2 as
17 (select id,
18 column_value cv,
19 regexp_substr(col2, '[^ ]+', 1, column_value) word
20 from test cross join
21 table(cast(multiset(select level from dual
22 connect by level <= regexp_count(col2, ' ') + 1
23 ) as sys.odcinumberlist))
24 )
25 -- final result
26 select a.id,
27 listagg(b.word, ' ') within group (order by a.cv) result
28 from sent2 b join sent1 a on a.id = b.id and a.cv = b.cv and a.word <> b.word
29 group by a.id;
ID RESULT
---------- ------------------------------
1 are flowers chair
SQL>

how to sum effectively, when rows should be in more groups Oracle

I have some records (over 1 million) which are consist from GROUPS of companies, but some records belong to several groups and I need to get total sum of groups (main (column C216) and secondary(column LIST_OF_PARENT_CCN))
In column LIST_OF_PARENT_CCN is any number of group IDs with semicolon ",", you can see it in table RR_SRC_LEK_P5.
I created table with companies group and sums (RR_SRC_LEK_P5) and filled the sum through the cursor. This solution is working, but is slow and not effective.
table RR_SRC_LEK_P5 looks like:
C216 LIST_OF_PARENT_CCN ESS_SUM
00004146 4523401 0
00005354 5487228, 2103188 0
00006203 0
00007524 2196702, 2103188 0
00009164 2163921, 4523401 0
table RR_SRC_LEK_P6 contains only total sums of PARENT_CCN
PARENT_CCN ESS_SUM
4523401 258418650,7711
5487228 2534044,19664
2103188 13482783356,0255
2196702 9936875,58
2163921 141329781,3349
result should be this, offcourse in column ESS_SUM is only one number
C216 LIST_OF_PARRENT_CCN ESS_SUM
00004146 4523401 258418650,7711
00005354 5487228, 2103188 2534044,19664 + 2534044,19664
00006203 0
00007524 2196702, 2103188 9936875,58 + 13482783356,0255
00009164 2163921, 4523401 141329781,3349 + 4523401
there is cursor, i used execute immediate
CREATE OR REPLACE PROCEDURE CURSOR_TEST AS
c_sql sys_refcursor;
c_C216 RR_SRC_LEK_P5.C216%TYPE;
c_LIST_OF_PARENT_CCN RR_SRC_LEK_P5.LIST_OF_PARENT_CCN%TYPE;
BEGIN
OPEN c_sql for 'select C216, LIST_OF_PARENT_CCN from RR_SRC_LEK_P5 where LIST_OF_PARENT_CCN is not null';
LOOP
FETCH c_sql into c_C216, c_LIST_OF_PARENT_CCN;
EXIT WHEN c_sql%notfound;
execute immediate 'update RR_SRC_LEK_P5 a set
ESS_SUM = (select sum(ESS_SUM) from RR_SRC_LEK_P6 where PARENT_CCN in (' || c_LIST_OF_PARENT_CCN || '))
where a.C216 = ''' || c_C216 || '''';
END LOOP;
CLOSE c_sql;
commit;
END CURSOR_TEST;
is there a better better way than use cursor?
You can use an aggregate function with xmlquery:
Table creation:
SQL> CREATE TABLE RR_SRC_LEK_P5 AS (
2 SELECT '00004146' AS C216, '4523401' AS LIST_OF_PARENT_CCN, 0 AS ESS_SUM FROM DUAL UNION ALL
3 SELECT '00005354', '5487228, 2103188', 0 FROM DUAL UNION ALL
4 SELECT '00006203', NULL ,0 FROM DUAL UNION ALL
5 SELECT '00007524', '2196702, 2103188', 0 FROM DUAL UNION ALL
6 SELECT '00009164', '2163921, 4523401', 0 FROM DUAL);
Table created.
SQL> CREATE TABLE RR_SRC_LEK_P6 AS
2 (SELECT 4523401 AS PARENT_CCN, 2584186507711 AS ESS_SUM FROM DUAL UNION ALL
3 SELECT 5487228, 253404419664 FROM DUAL UNION ALL
4 SELECT 2103188, 134827833560255 FROM DUAL UNION ALL
5 SELECT 2196702, 993687558 FROM DUAL UNION ALL
6 SELECT 2163921, 1413297813349 FROM DUAL);
Table created.
SQL>
View of current data
SQL> select * from RR_SRC_LEK_P5;
C216 LIST_OF_PARENT_C ESS_SUM
-------- ---------------- ----------
00004146 4523401 0
00005354 5487228, 2103188 0
00006203 0
00007524 2196702, 2103188 0
00009164 2163921, 4523401 0
SQL> select * from RR_SRC_LEK_P6;
PARENT_CCN ESS_SUM
---------- ---------------------------------------
4523401 2584186507711
5487228 253404419664
2103188 134827833560255
2196702 993687558
2163921 1413297813349
SQL>
Query to update data
SQL>
SQL> MERGE INTO RR_SRC_LEK_P5 P5
2 USING ( SELECT P5.C216,
3 XMLQUERY(
4 LISTAGG(P6.ESS_SUM, '+') WITHIN GROUP (ORDER BY NULL)
5 RETURNING CONTENT ).GETNUMBERVAL() AS ESS_NEW
6 FROM RR_SRC_LEK_P5 P5
7 JOIN RR_SRC_LEK_P6 P6
8 ON ( INSTR(', ' || P5.LIST_OF_PARENT_CCN || ',',
9 ', ' || P6.PARENT_CCN || ',') > 0 )
10 GROUP BY P5.C216) RES
11 ON ( P5.C216 = RES.C216 )
12 WHEN MATCHED THEN
13 UPDATE SET P5.ESS_SUM = RES.ESS_NEW;
4 rows merged.
SQL>
Updated data
SQL> SELECT * FROM RR_SRC_LEK_P5;
C216 LIST_OF_PARENT_C ESS_SUM
-------- ---------------- ---------------------------------------
00004146 4523401 2584186507711
00005354 5487228, 2103188 135081237979919
00006203 0
00007524 2196702, 2103188 134828827247813
00009164 2163921, 4523401 3997484321060
SQL>
DB<>Fiddle demo
Update
For your settings, you need to use following query:
MERGE INTO RR_SRC_LEK_P5 P5
USING ( SELECT P5.C216,
XMLQUERY(
LISTAGG(
to_char(p6.ESS_SUM,
'fm9999999999999999999999999999D099999999999999999',
'nls_numeric_characters = ''.,'''), '+') WITHIN GROUP (ORDER BY NULL)
RETURNING CONTENT ).GETNUMBERVAL() AS ESS_NEW
FROM RR_SRC_LEK_P5 P5
JOIN RR_SRC_LEK_P6 P6
ON ( INSTR(', ' || P5.LIST_OF_PARENT_CCN || ',',
', ' || P6.PARENT_CCN || ',') > 0 )
GROUP BY P5.C216) RES
ON ( P5.C216 = RES.C216 )
WHEN MATCHED THEN
UPDATE SET P5.ESS_SUM = RES.ESS_NEW;
Cheers!!

Printing with loops in sql

Hi I wrote a procedure to accomplish a task and it looks like this
create or replace procedure myproc
is
begin
for rec_ in (
select
case
when highest_ = 1 then
'Most profit in ' || category || ' -> ' || carname || ': ' || aprofit
when lowest_ = 1 then
'Least profit in ' || category || ' -> ' || carname || ': ' || aprofit
end report
from (
select
category
, carname
, aprofit
, rank() over ( partition by category order by aprofit asc ) lowest_
, rank() over ( partition by category order by aprofit desc ) highest_
from (
select unique
C.category
, C.carname
, avg( R.rentalrate - C.suggesteddealerrentalprice )
over ( partition by C.category, C.carname ) as aprofit
from rentals R
join car C on R.carid = C.carid
join cardealers CD on CD.dealerid = C.dealerid
where CD.state = 'IN'
)
)
where lowest_ = 1 or highest_ = 1
order by case when lowest_ > 1 then 2 else 1 end, category, carname
)
loop
dbms_output.put_line( rec_.report ) ;
end loop ;
end ;
/
begin
myproc ;
end ;
/
This prints out the output that looks like this
Least profit in compact -> Nissan Versa: 4
Least profit in compact -> Toyota Yaris: 4
Least profit in luxury -> Porsche: 40
Least profit in van -> Chrysler: 2
Most profit in compact -> Chevy Spark: 5
Most profit in luxury -> Audi: 45
Most profit in van -> Honda Odyssey: 9
I want it to print out like this that if a car category has more than one car inside it it only prints the heading one time. But as you can see in my output the heading for "Least profit in compact" is being printed two times. I want an output that looks like this
Least Profit in compact
- Nissan Versa: 4
- Toyota Yaris: 4
Least Profit in luxury
- Porsche: 40
Least Profit in van
- Chrysler: 2
Most Profit in compact
- Chevy Spark: 5
Most Profit in luxury
- Audi: 45
Most Profit in van
- Honda Odyssey: 9
The tables and data files are
Data file
Tables file
You may select the columns Least/Most,category,carname,aprofit separately from your select query and then use DBMS_OUTPUT conditionally.
I have used your sample dataset from the output in the below code as I do not have your table/ definitions.
DECLARE
v_high_low VARCHAR2(40) := 'DUMMY';
v_category VARCHAR2(40) := 'DUMMY';
BEGIN
for rec_ IN
(
with t (high_low,category,carname,aprofit) AS
(
select 'Least profit in ','compact', 'Nissan Versa', 4 from dual union all
select 'Least profit in ','compact','Toyota Yaris', 4 from dual union all
select 'Least profit in ','luxury','Porsche', 40 from dual union all
select 'Least profit in ','van','Chrysler', 2 from dual union all
select 'Most profit in ','compact','Chevy Spark', 5 from dual union all
select 'Most profit in ','luxury','Audi', 45 from dual union all
select 'Most profit in ','van', 'Honda Odyssey', 9 from dual
)
SELECT * FROM t order by high_low,category,carname
)
LOOP
IF rec_.high_low != v_high_low OR rec_.category != v_category
THEN
DBMS_OUTPUT.PUT(rec_.high_low);
v_high_low := rec_.high_low;
END IF;
IF rec_.category != v_category
THEN
DBMS_OUTPUT.PUT_LINE(rec_.category);
v_category := rec_.category;
END IF;
DBMS_OUTPUT.PUT_LINE(' - '||rec_.carname||': '|| rec_.aprofit);
END LOOP;
END;
/
DEMO
EDIT - Adding this demo link with the procedure with actual tables provided :
DEMO2

Insert New Value from another field value in the same row (using oracle database)

I have two tables (MST_IP and MST_ROUTER) like this below:
MST_IP
SEQ IP_NUMBER STATUS
1 12.123.0.0 0
2 12.123.0.1 0
3 12.104.0.1 0
4 12.104.0.2 0
5 13.123.0.1 0
6 13.123.0.2 0
7 11.555.8.1 0
8 11.555.8.2 0
I want to insert IP_NUMBER from MST_IP to MST_ROUTER (IP_NUMBER and REMOTE_NUMBER). What I want the data will be like this below.
MST_ROUTER
USER_ID IP_NUMBER REMOTE_NUMBER
AA 12.123.0.0 12.123.0.1
BB 12.104.0.1 12.104.0.2
CC 13.123.0.1 13.123.0.2
DD 11.555.8.1 11.555.8.2
below is my code.
/* Formatted on 9/28/2017 11:44:11 AM (QP5 v5.115.810.9015) */ SET SERVEROUTPUT ON
DECLARE INS VARCHAR2 (100); INS2 VARCHAR2 (100); SEQ_R INTEGER; BEGIN SEQ_R := 1;
SELECT IP_NUMBER
INTO INS
FROM ( SELECT *
FROM MST_IP
WHERE STATUS = 0
ORDER BY SEQ ASC)
WHERE ROWNUM = 1;
SELECT IP_NUMBER
INTO INS2
FROM ( SELECT *
FROM MST_IP
WHERE STATUS = 0 AND SEQ = SEQ_R + 1
ORDER BY SEQ ASC)
WHERE ROWNUM = 1;
INSERT INTO MST_ROUTER (USER_ID, IP_NUMBER)
VALUES ('HMJ-BKS', INS);
COMMIT;
UPDATE MST_IP
SET STATUS = 1
WHERE IP_NUMBER = INS;
COMMIT;
UPDATE MST_ROUTER
SET REMOTE_NUMBER = INS2
WHERE USER_ID = 'HMJ-BKS';
COMMIT;
UPDATE MST_IP
SET STATUS = 1
WHERE IP_NUMBER = INS2;
COMMIT;
DBMS_OUTPUT.PUT_LINE (INS); END; /
In my code, I change STATUS on MST_IP = 1 if the data already inserted in MST_ROUTER. The problem my code is not working after for insert the second row. Any comment will be appreciate.
One trick to bring the local and remote IP addresses in line with each other is to join a subquery of local addresses to their remote counterparts, and then insert this result into the MST_ROUTER table.
INSERT INTO MST_ROUTER (USER_ID, IP_NUMBER, REMOTE_NUMBER)
SELECT
CAST(t1.SEQ / 2 AS UNSIGNED) AS SEQ, t1.IP_NUMBER, t2.IP_NUMBER
FROM
(
SELECT SEQ - 1 AS SEQ, IP_NUMBER
FROM MST_IP
WHERE MOD((SEQ - 1), 2) = 0
) t1
LEFT JOIN MST_IP t2
ON t1.SEQ = t2.SEQ - 2
Below is a link to a demo which shows the output of the select component of my query.
Demo
Output:
SEQ IP_NUMBER IP_NUMBER
0 12.123.0.0 12.123.0.1
1 12.104.0.1 12.104.0.2
2 13.123.0.1 13.123.0.2
3 11.555.8.1 11.555.8.2

Find the greatest version

I am using Oracle Database 11g Enterprise Edition Release 11.2.0.2.0
I have a table as follows:
Table1:
Name Null Type
----------------- -------- -------------
NAME NOT NULL VARCHAR2(64)
VERSION NOT NULL VARCHAR2(64)
Table1
Name Version
---------------
A 1
B 12.1.0.2
B 8.2.1.2
B 12.0.0
C 11.1.2
C 11.01.05
I want the output as:
Name Version
---------------
A 1
B 12.1.0.2
C 11.01.05
Basically, I want to get the row for each name which have highest version. For this I am using the following query:
SELECT t1.NAME,
t1.VERSION
FROM TABLE1 t1
LEFT OUTER JOIN TABLE1 t2
on (t1.NAME = t2.NAME and t1.VERSION < t2.VERSION)
where t2.NAME is null
Now 't1.VERSION < t2.VERSION' only works in normal version cases but in cases such as:
B 12.1.0.2
B 8.2.1.2
It fails, I need a PL/SQL script to normalize the version strings and compare them for higher value.
You can do this with judicious use of REGEXP_SUBSTR(); there's no need to use PL/SQL.
select *
from ( select a.*
, row_number() over (
partition by name
order by to_number(regexp_substr(version, '[^.]+', 1, 1)) desc
, to_number(regexp_substr(version, '[^.]+', 1, 2)) desc
, to_number(regexp_substr(version, '[^.]+', 1, 3)) desc
, to_number(regexp_substr(version, '[^.]+', 1, 4)) desc
) as rnum
from table1 a )
where rnum = 1
Here's a SQL Fiddle to demonstrate. Please note how I've had to convert each portion to a number to avoid a binary sort on numbers not between 0 and 9.
However, I cannot emphasise enough how much easier your life would be if you separated these up into different columns, major version, minor version etc. You could then have a virtual column that concatenates them all together to ensure that your export is always standardised, should you wish.
If, for instance, you created a table as follows:
create table table1 (
name varchar2(64)
, major number
, minor number
, build number
, revision number
, version varchar2(200) generated always as (
to_char(major) || '.' ||
to_char(minor) || '.' ||
to_char(build) || '.' ||
to_char(revision)
)
Your query becomes simpler to understand; also in SQL Fiddle
select name, version
from ( select a.*
, row_number() over (
partition by name
order by major desc
, minor desc
, build desc
, revision desc ) as rnum
from table1 a )
where rnum = 1
This solution is independent on how many numerical parts are inside version code.
It only assumes that every numerical part consists of not more than 6 digits.
select
name,
max(version) keep (dense_rank first order by version_norm desc)
as max_version
from (
select
t.*,
regexp_replace(
regexp_replace('000000'||version, '\.', '.000000')||'.',
'\d*(\d{6}\.)', '\1')
as version_norm
from table1 t
)
group by name
SQL Fiddle
You somehow need to convert the string values into numeric values, and then scale them by some appropriate multiplier. Assume that each version value must be a number between 0..99 as an example. So, if your string was "8.2.1.2", you would scale the numeric values of the string, "a.b.c.d" = d + c*100 + b*10000 + a*1000000, = 2 + 100 + 20000 + 8000000 =
8020102, then you can use that value to order.
I found a function you can use to parse a token from a delimited string:
CREATE OR REPLACE FUNCTION get_token (the_list VARCHAR2,
the_index NUMBER,
delim VARCHAR2 := ',')
RETURN VARCHAR2
IS
start_pos NUMBER;
end_pos NUMBER;
BEGIN
IF the_index = 1
THEN
start_pos := 1;
ELSE
start_pos :=
INSTR (the_list,
delim,
1,
the_index - 1);
IF start_pos = 0
THEN
RETURN NULL;
ELSE
start_pos := start_pos + LENGTH (delim);
END IF;
END IF;
end_pos :=
INSTR (the_list,
delim,
start_pos,
1);
IF end_pos = 0
THEN
RETURN SUBSTR (the_list, start_pos);
ELSE
RETURN SUBSTR (the_list, start_pos, end_pos - start_pos);
END IF;
END get_token;
so call something like
select to_number(get_token(version,1,'.'))*1000000 + to_number(get_token(version,2,'.'))*10000 + .. etc.
Just wrote a MySQL user defined function to accomplish the task, you can easily port it to ORACLE PL/SQL.
DELIMITER $$
DROP FUNCTION IF EXISTS `VerCmp`$$
CREATE FUNCTION VerCmp (VerX VARCHAR(64), VerY VARCHAR(64), Delim CHAR(1))
RETURNS INT DETERMINISTIC
BEGIN
DECLARE idx INT UNSIGNED DEFAULT 1;
DECLARE xVer INT DEFAULT 0;
DECLARE yVer INT DEFAULT 0;
DECLARE xCount INT UNSIGNED DEFAULT 0;
DECLARE yCount INT UNSIGNED DEFAULT 0;
DECLARE counter INT UNSIGNED DEFAULT 0;
SET xCount = LENGTH(VerX) - LENGTH(REPLACE(VerX, Delim,'')) +1;
SET yCount = LENGTH(VerY) - LENGTH(REPLACE(VerY, Delim,'')) +1;
IF xCount > yCount THEN
SET counter = xCount;
ELSE
SET counter = yCount;
END IF;
WHILE (idx <= counter) DO
IF (xCount >= idx) THEN
SET xVer = SUBSTRING_INDEX(SUBSTRING_INDEX(VerX, Delim, idx), Delim, -1) +0;
ELSE
SET xVer =0;
END IF;
IF (yCount >= idx) THEN
SET yVer = SUBSTRING_INDEX(SUBSTRING_INDEX(VerY, Delim, idx), Delim, -1) +0;
ELSE
SET yVer = 0;
END IF;
IF (xVer > yVer) THEN
RETURN 1;
ELSEIF (xVer < yVer) THEN
RETURN -1;
END IF;
SET idx = idx +1;
END WHILE;
RETURN 0;
END$$;
DELIMITER ;
Few test that I ran:
select vercmp('5.2.4','5.2.5','.');
+------------------------------+
| vercmp('5.2.4','5.2.5','.') |
+------------------------------+
| -1 |
+------------------------------+
select vercmp('5.2.4','5.2.4','.');
+------------------------------+
| vercmp('5.2.4','5.2.4','.') |
+------------------------------+
| 0 |
+------------------------------+
select vercmp('5.2.4','5.2','.');
+----------------------------+
| vercmp('5.2.4','5.2','.') |
+----------------------------+
| 1 |
+----------------------------+
select vercmp('1,2,4','5,2',',');
+----------------------------+
| vercmp('1,2,4','5,2',',') |
+----------------------------+
| -1 |
+----------------------------+

Resources