Swap fields inside an Oracle record using couple separator * and elements separator | - oracle

In an Oracle table, I have record with COUPLES (string,number) so separated:
Abc|3456*Def|7890*Ghi|9430*Jkl|3534
In the previous example, the couples are:
(Abc,3456)
(Def,7890)
(Ghi,9430)
(Jkl,3534)
I would like to modify each record swapping the order of every couple (first the number, then the string):
3456|Abc*7890|Def*9430|Ghi*3534|Jkl
The separator of the two elements of a couple is pipe (|).
The SEPARATOR BETWEEN COUPLES is asterisk (*).
How can I achieve my objective to swap the order of every couple?
Thank you in advance for your kind cooperation!

Try using regular expressions...now you've got two problems:
select
cola,
regexp_replace(cola, '([^*|]*)\|([^*|]*)(\*|$)','\2|\1\3') as swapped_col
from (
select '3456|Abc*7890|Def*9430|Ghi*3534|Jkl' cola from dual
)
Basically the regex is saying search for everything that isn't a | or a * until you find |, then find everything that isn't a | or * until you find a * or then end of the string. Then swap the two bits and terminate it with the character you found as the final separator (either * or EOL). The bits that are swapped are grouped by the round brackets then in the replace string the numbers denote which is placed where... so the contents of the second set of brackets is put first, then a vertical bar, then the first set of brackets, then the third.
By default, REGEXP_REPLACE will replace every occurrence that it finds of the pattern and replace it

Related

Replacing only 3rd to 6th position of a String

I am new to SQL. I want to replace only 3rd to 6th(only 1st 1234) position of below string with '1219', but its replacing whole new string:
SELECT REPLACE('DD123412341234',SUBSTR('DD123412341234',3,4),'1219' ) FROM DUAL;
Kindle suggest on the same.
You can do it with function regexp_replace.
select regexp_replace('DD123412341234','....','1219',3,1) as RESULT from DUAL
As stated in the documentation, the second function parameter is the regular expression to search for which, in this case, is any four characters. The third parameter is the replacement string. The fourth [optional] parameter indicates to start the search from the third character and the final [also optional] parameter means only search for the first occurrence and replace that first occurrence with 1219.
The result of the above query is DD121912341234
Regular expressions tend to be relatively slow. Since you know the specific location to replace an alternative would be sub the parts to be kept and rebuild with the concatenation operator. The following may be faster, but it does involve more operations.
with test(t) as
(select 'DD123412341234' from dual)
select substr(t,1,2) || '1219' || substr(t,7)
from test;

Looking for Special characters in MonetDB table columns

I am new to MonetDB, I would like to check if there are any special characters in any of the columns in MonetDB.
For example, I have a test Database and the table name is Lmr. I would be to check if any of the columns in table lmr contains special characters?
The query I tried:
SELECT jk
FROM lmr
WHERE jk like '%[^a-Z0-9]%'
I have multiple columns, so is there any way where I can check all the columns with a special character at once?
The LIKE and ILIKE operators use PCRE internally, but do not expose the same expressive power. Basically you can only use % as wildcards.
Luckily, MonetDB already provides wrappers to the PCRE library. For some reason that I am not aware of, they are not made available by default at the SQL layer.
In order to do that, you only need to create SQL function signatures that link to the code that is already available:
CREATE OR REPLACE FUNCTION pcre_match(s string, pattern string) RETURNS boolean EXTERNAL NAME pcre."match";
CREATE OR REPLACE FUNCTION pcre_imatch(s string, pattern string) RETURNS boolean EXTERNAL NAME pcre."imatch";
CREATE OR REPLACE FUNCTION pcre_replace(s string, pattern string, repl string, flags string) RETURNS string EXTERNAL NAME pcre."replace";
CREATE OR REPLACE FUNCTION pcre_replacefirst(s string, pattern string, repl string, flags string) RETURNS string EXTERNAL NAME pcre."replace_first";
After that (to be done only once in a database), you can do:
SELECT jk
FROM lmr
WHERE pcre_imatch(jk,'[^a-z0-9]');
The second parameter is a regular PCRE pattern.
Mind that you had an error in your example. The range a-Z does not exist, because a comes after Z.
In my example I used the i (ignore case) variant of the function, and only used range a-z.
If you want you can also use Unicode categories and rewrite your example to match everything that is not a letter or a number as:
SELECT jk
FROM lmr
WHERE pcre_imatch(jk,'[^\\p{L}\\p{N}]');
Mind that you need to escape each \, which becomes then \\.
About checking multiple columns at once, assuming that you want to return the rows where the condition is satisfied on any of the given columns, you could do this (for 3 columns here):
SELECT col1,col2,col3
FROM lmr
WHERE pcre_imatch(col1 || col2 || col3,'[^\\p{L}\\p{N}]');
where || is string concatenation.
The problem with this is that it first needs to concatenate all columns together. Because MonetDB is a column-store, it will do this for all rows at once. So it will first materialize in memory (and/or disk) all columns for all rows. I'm not sure how much data you have, but that is potentially very big.
The other approach is of course:
SELECT col1,col2,col3
FROM lmr
WHERE pcre_imatch(col1,'[^\\p{L}\\p{N}]')
OR pcre_imatch(col2,'[^\\p{L}\\p{N}]')
OR pcre_imatch(col3,'[^\\p{L}\\p{N}]');
I think I would choose the second approach, as it definitely has a much smaller memory footprint.

How to load data into Oracle using SQL Loader with skipping and merging columns?

I am trying to load data into Oracle database using sqlloader,
My data looks like following.
1|2|3|4|5|6|7|8|9|10
I do not want to load first and last column into table,
I want to load 2|3|4|5|6|7|8|9 into one field.
The table I am trying to load into has only one filed named 'field1'.
If anyone has this kind of experience, could you give some advice?
I tried BOUNDFILLER, FILLER and so on, I could not make it.
Help me. :)
Load the entire row from the file into a BOUNDFILLER, then extract the part you need into the column. You have to tell sqlldr that the field is terminated by the carriage return/linefeed (assuming a Windows OS) so it will read the entire line from the file as one field. here the whole line from the file is read into "dummy" as BOUNDFILLER. "dummy" does not match a column name, and it's defined as BOUNDFILLER anyway, so the whole row is "remembered". The next line in the control file starts with a column that DOES match a column name, so sqlldr attempts to execute the expression. It extracts a substring from the saved "dummy" and puts it into the "col_a" column.
The regular expression in a nutshell returns the part of the string after but not including the first pipe, and before but not including the last pipe. Note the double backslashes. In my environment anyway, when using a backslash to take away the special meaning of the pipe (not needed when between the square brackets) it gets stripped when passing from sqlldr to the regex engine so two backslashes are required in the control file
(normally a pipe symbol is a logical OR) so one gets through in the end. If you have trouble here, try one backslash and see what happens. Guess how long THAT took me to figure out!
load data
infile 'x_test.dat'
TRUNCATE
into table x_test
FIELDS TERMINATED BY x'0D0A'
(
dummy BOUNDFILLER,
col_a expression "regexp_substr(:dummy, '[^|]*\\|(.+)\\|.*', 1, 1, NULL, 1)"
)
EDIT: Use this to test the regular expression. For example, if there is an additional pipe at the end:
select regexp_substr('1|2|3|4|5|6|7|8|9|10|', '[^|]*\|(.+)\|.*\|', 1, 1, NULL, 1)
from dual;
2nd edit: For those uncomfortable with regular expressions, this method uses nested SUBSTR and INSTR functions:
SQL> with tbl(str) as (
select '1|2|3|4|5|6|7|8|9|10|' from dual
)
select substr(str, instr(str, '|')+1, (instr(str, '|', -1, 2)-1 - instr(str
, '|')) ) after
from tbl;
AFTER
---------------
2|3|4|5|6|7|8|9
Deciding which is easier to maintain is up to you. Think of the developer after you and comment at any rate! :-)

Inserting/Updating numeric string in Sqlite with Ruby (Newbie query)

I have a simple Sqlite table with 2 columns for a telephone number and a counter. I want to update the table on the basis of .csv files that also contain telephone numbers and counters. If the number exists in the database it should be updated by the sum of the existing counter + the counter in the file. If it doesn't exist a new record should be inserted with the value from the file.
My one remaining problem is that the telephone numbers have a zero in the first position.
When I populate the db the zero is retained, (I can manually select and find an existing number like 09999) when I fetch the values from the file the zero is retained but when I try to insert/update something happens in my Ruby code that inserts a new record without the leading zero, so 0999 becomes 999 in the db. Numbers without leading zeros are handled correctly.
My code looks like this:
rowArray=thisFile[k].split(';')
number = rowArray[0]
couplings = rowArray[1]
updString="INSERT OR REPLACE INTO Caller (Telno,count) VALUES (#{number},COALESCE((SELECT count + #{couplings} FROM Caller WHERE Telno=#{number}),# {couplings}))"
db.execute(updString)
Any idea what I'm doing wrong here? The easiest solution would be to drop the leading zero but I would prefer to do it right. Many thanks in advance.
You need to use placeholders in your prepare call and pass the actual values in a call to execute. Like this
insert = db.prepare(<<__SQL__)
INSERT OR REPLACE INTO Caller (Telno, count)
VALUES (:number, COALESCE((SELECT count + :couplings FROM Caller WHERE Telno = :number), :couplings))
__SQL__
insert.execute(number: number, couplings: couplings)
(Note that :number and :couplings in the SQL statement are named placeholders. They can be anything, but I have chosen them to match the corresponding names of the variables that are to be bound.)
The problem is that, using simple interpolation, you end up with a string like
INSERT OR REPLACE INTO Caller (Telno, count) VALUES (0999, ...
and the 0999 appears to be a number rather than a string. If you pass strings to execute then the variables will be bound with the correct type.

make a sequence in oracle database

How can I create a sequence, which has two parts one fixed characters part and another variable integer part like "LTR00001" and the next value in the sequence should be "LTR00002"
You cannot. Sequences are just integers.
But you can select a formatted string from the sequence
SELECT 'LTR' || to_char('09999', the_sequence.nextval) FROM DUAL;

Resources