Oracle SQL select query that return results with diacritis inside the name - sql

Hello I have a Java app that runs an Oracle SQL select query that returns some results.
This is the select:
select a,b,c where a='%ruicanescu%'
This returns only results where the name is exactly 'ruicanescu' but I would like also to return for example: 'ruicănescu' and other diacritics inside the name. Can someone give me an example ? Thanks

You could use CONVERT:
SELECT a, b, c
FROM table_name
WHERE CONVERT(a, 'US7ASCII') LIKE '%ruicanescu%';
Or you can set the NLS_SORT and NLS_COMP session parameters to accent insensitive matching:
ALTER SESSION SET NLS_COMP='LINGUISTIC';
ALTER SESSION SET NLS_SORT='BINARY_AI';
SELECT a, b, c
FROM table_name
WHERE a LIKE '%ruicanescu%';
Which, for the sample data:
CREATE TABLE table_name (a, b, c) AS
SELECT 'ruicănescu', 1, 1 FROM DUAL UNION ALL
SELECT 'ruicanescu', 2, 2 FROM DUAL;
Both output:
A
B
C
ruicănescu
1
1
ruicanescu
2
2
db<>fiddle here

Related

Is there something like Spark's unionByName in BigQuery?

I'd like to concatenate tables with different schemas, filling unknown values with null.
Simply using UNION ALL of course does not work like this:
WITH
x AS (SELECT 1 AS a, 2 AS b ),
y AS (SELECT 3 AS b, 4 AS c )
SELECT * FROM x
UNION ALL
SELECT * FROM y
a b
1 2
3 4
(unwanted result)
In Spark, I'd use unionByName to get the following result:
a b c
1 2
3 4
(wanted result)
Of course, I can manually create the needed query (adding nullss) in BigQuery like so:
SELECT a, b, NULL c FROM x
UNION ALL
SELECT NULL a, b, c FROM y
But I'd prefer to have a generic solution, not requiring me to generate something like that.
So, is there something like unionByName in BigQuery? Or can one come up with a generic SQL function for this?
Consider below approach (I think it is as generic as one can get)
create temp function json_extract_keys(input string) returns array<string> language js as """
return Object.keys(JSON.parse(input));
""";
create temp function json_extract_values(input string) returns array<string> language js as """
return Object.values(JSON.parse(input));
""";
create temp table temp_table as (
select json, key, value
from (
select to_json_string(t) json from table_x as t
union all
select to_json_string(t) from table_y as t
) t, unnest(json_extract_keys(json)) key with offset
join unnest(json_extract_values(json)) value with offset
using(offset)
order by key
);
execute immediate(select '''
select * except(json) from temp_table
pivot (any_value(value) for key in ("''' || string_agg(distinct key, '","') || '"))'
from temp_table
)
if applied to sample data in your question - output is

How to chose Table based on parameterized database name?

My code takes in a parameter ${ID}$ (string) and based on what ID evaluates to I want to chose a different table to use. Guess I cant use a case inside a FROM statement. Some example code looks like:
select *
from ${ID}$_charges.transaction_charge
where execution_date = '2011-03-22'
So if ID is 'N' then I want to use the transaction_charge table so the statement resolves to N_charges.transaction_charge
However if ID is 'B' or 'P' then I want to use a different table called conformity_charge and the statement would evaluate to B_charges.conformity_charge or P_charges.conformity_charge
How can I write this statement?
If you have a low number of possible tables to target, the closest you can get, apart from dynamic SQL, is:
NOTE: Depending of the capabilities of your database engine and the size of your tables there might be performance penalties that may or may not matter.
SELECT a, b, c
FROM (
SELECT 'N' as TableName, a, b, c
FROM N_charges.transaction_charge
UNION ALL
SELECT 'P' as TableName, a, b, c
FROM P_charges.transaction_charge
UNION ALL
SELECT 'B' as TableName, a, b, c
FROM B_charges.transaction_charge
) t
WHERE TableName = '${ID}$'
# Another variation
SELECT a, b, c
FROM N_charges.transaction_charge
WHERE 'N' = '${ID}$'
UNION ALL
SELECT a, b, c
FROM P_charges.transaction_charge
WHERE 'P' = '${ID}$'
UNION ALL
SELECT a, b, c
FROM B_charges.transaction_charge
WHERE 'B' = '${ID}$'

To check if string contains specific number or not

I have two columns in two different tables.
First column is number like 0493484402 and second column is audit_detail like 'addr_mastersubscription has changed from 32488141893 to 32488141973'.
Audit detail column may have different type of string other than above. I have to check only in above type mentioned strings
I have to check whether first column value is present or not in second column at position of Second number.
If the number is not present I need that number as output
I am using oracel SQL developer
Second column datatype is clob and there is not comman filed in both table's
First column data type is varchar
Use REGEXP_LIKE:
SELECT *
FROM yourTable
WHERE REGEXP_LIKE (col2, ' to ' || col1 || '$');
You need to check the two conditions then you can use REGEXP_SUBSTR and REGEXP_LIKE as follows:
SELECT * FROM YOUR_TABLE
WHERE REGEXP_LIKE(SECOND_COLUMN, '^addr_mastersubscription has changed from [0-9]+ to [0-9]+$')
AND TO_NUMBER(FIRST_COLUMN) = TO_NUMBER(REGEXP_SUBSTR(SECOND_COLUMN,'[0-9]+$'))
This is how I understood the question.
Sample data (lines #1 - 9) contain additional ID column (unless you're planning to do cross join between those two tables) which is used to join taba and tabb.
regexp_substr looks for the second number in tabb's col column, which is compared to taba.col. I displayed whether it exists there or not; you can display whatever you want.
Query you might need begins at line #11.
SQL> with
2 taba (id, col) as
3 (select 1, '0493484402' from dual union all
4 select 2, '012345' from dual
5 ),
6 tabb (id, col) as
7 (select 1, 'addr_mastersubscription has changed from 32488141893 to 32488141973' from dual union all
8 select 2, 'nothing changed from 098776 to 012345' from dual
9 )
10 --
11 select a.id,
12 case when a.col = regexp_substr(b.col, '\d+', 1, 2) then a.col || ' exists in tabb'
13 else a.col || ' does not exist in tabb'
14 end result
15 from taba a join tabb b on a.id = b.id;
ID RESULT
---------- ---------------------------------
1 0493484402 does not exist in tabb
2 012345 exists in tabb
SQL>
You can use INSTR(), names itself defines in string where we can check if a particular string is available in the respective column.
Please use below query,
select t1.* from table1 t1
inner join table2 t2
on (instr(t1.first_column, t2.second_column) = 0);
instr(t1.first_column, t2.second_column) = 0 This condition provides you unmatching columns
instr(t1.first_column, t2.second_column) > 0 This condition provides you matching strings

How to extract the table name from a CREATE/UPDATE/INSERT statement in an SQL query?

I am trying to parse the table being created, inserted into or updated from the following sql queries stored in a table column.
Let's call the table column query. Following is some sample data to demonstrate variations in how the data could look like.
with sample_data as (
select 1 as id, 'CREATE TABLE tbl1 ...' as query union all
select 2 as id, 'CREATE OR REPLACE TABLE tbl1 ...' as query union all
select 3 as id, 'DROP TABLE IF EXISTS tbl1; CREATE TABLE tbl1 ...' as query union all
select 4 as id, 'INSERT /*some comment*/ INTO tbl2 ...' as query union all
select 5 as id, 'INSERT /*some comment*/ INTO tbl2 ...' as query union all
select 6 as id, 'UPDATE tbl3 SET col1 = ...' as query union all
select 7 as id, '/*some garbage comments*/ UPDATE tbl3 SET col1 = ...' as query union all
select 8 as id, 'DELETE tbl4 ...' as query
),
Following are the formats of the queries (we are trying to extract table_name ):
#1
some optional statements like drop table
CREATE some comments or optional statement like OR REPLACE TABLE table_name
everything else
#2
some optional statements like drop table
INSERT some comments INTO some comments table_name
#3
some optional statements like drop table
UPDATE some comments table_name
everything else
Regular Expression
To construct a suitable regex, let's start with the following relatively simple/readable version:
((CREATE( OR REPLACE)?|DROP) TABLE( IF EXISTS)?|UPDATE|DELETE|INSERT INTO) ([^\s\/*]+)
All the spaces above could be replaced with "at least one whitespace character", i.e. \s+. But we also need to allow comments. For a comment that looks like /*anything*/ the regex looks like \/\*.*\*\/ (where the comment characters are escaped with \ and "anything" is the .* in the middle). Given there could be multiple such comments, optionally separated by whitespace, we end up with (\s*\/\*.*\*\/\s*?)*\s+. Plugging this in everywhere there was a space gives:
((CREATE((\s*\/\*.*\*\/\s*?)*\s+OR(\s*\/\*.*\*\/\s*?)*\s+REPLACE)?|DROP)(\s*\/\*.*\*\/\s*?)*\s+TABLE((\s*\/\*.*\*\/\s*?)*\s+IF(\s*\/\*.*\*\/\s*?)*\s+EXISTS)?|UPDATE|DELETE|INSERT(\s*\/\*.*\*\/\s*?)*\s+INTO)(\s*\/\*.*\*\/\s*?)*\s+([^\s\/*]+)
One further refinement needs to be made: Bracketed expressions have been used for choices, e.g. (CHOICE1|CHOICE2). But this syntax includes them as capturing groups. Actually we only require one capturing group for the table name so we can exclude all the other capturing groups via ?:, e.g. (?:CHOICE1|CHOICE2). This gives:
(?:(?:CREATE(?:(?:\s*\/\*.*\*\/\s*?)*\s+OR(?:\s*\/\*.*\*\/\s*?)*\s+REPLACE)?|DROP)(?:\s*\/\*.*\*\/\s*?)*\s+TABLE(?:(?:\s*\/\*.*\*\/\s*?)*\s+IF(?:\s*\/\*.*\*\/\s*?)*\s+EXISTS)?|UPDATE|DELETE|INSERT(?:\s*\/\*.*\*\/\s*?)*\s+INTO)(?:\s*\/\*.*\*\/\s*?)*\s+([^\s\/*]+)
Online Regex Demo
Here's a demo of it working with your examples: Regex101 demo
SQL
The Google BigQuery documentation for REGEXP_EXTRACT says it will return the substring matched by the capturing group. So I'd expect something like this to work:
with sample_data as (
select 1 as id, 'CREATE TABLE tbl1 ...' as query union all
select 2 as id, 'CREATE OR REPLACE TABLE tbl1 ...' as query union all
select 3 as id, 'DROP TABLE IF EXISTS tbl1; CREATE TABLE tbl1 ...' as query union all
select 4 as id, 'INSERT /*some comment*/ INTO tbl2 ...' as query union all
select 5 as id, 'INSERT /*some comment*/ INTO tbl2 ...' as query union all
select 6 as id, 'UPDATE tbl3 SET col1 = ...' as query union all
select 7 as id, '/*some garbage comments*/ UPDATE tbl3 SET col1 = ...' as query union all
select 8 as id, 'DELETE tbl4 ...' as query
)
SELECT
*, REGEXP_EXTRACT(query, r"(?:(?:CREATE(?:(?:\s*\/\*.*\*\/\s*?)*\s+OR(?:\s*\/\*.*\*\/\s*?)*\s+REPLACE)?|DROP)(?:\s*\/\*.*\*\/\s*?)*\s+TABLE(?:(?:\s*\/\*.*\*\/\s*?)*\s+IF(?:\s*\/\*.*\*\/\s*?)*\s+EXISTS)?|UPDATE|DELETE|INSERT(?:\s*\/\*.*\*\/\s*?)*\s+INTO)(?:\s*\/\*.*\*\/\s*?)*\s+([^\s\/*]+)") AS table_name
FROM sample_data;
(The above is untested so please let me know in the comments if there are any issues.)
I think it really depends on your data, but you might find some success using an approach like this:
with data as (
select 1 as id, 'CREATE TABLE tbl1 ...' as query union all
select 2 as id, 'INSERT INTO tbl2 ...' as query union all
select 3 as id, 'UPDATE tbl3 ...' as query union all
select 4 as id, 'DELETE tbl4 ...' as query
),
splitted as (
select id, split(query, ' ') as query_parts from data
)
select
id,
case
when query_parts[safe_offset(0)] in('CREATE', 'INSERT') then query_parts[safe_offset(2)]
when query_parts[safe_offset(0)] in('UPDATE', 'DELETE') then query_parts[safe_offset(1)]
else 'Error'
end as table_name
from splitted
Of course this depends on the cleanliness and syntax in your query column. Also, if your table_name is qualified with project.table.dataset you would need to do further splitting.

SQL search results in order of what was searched

I want the server to give me the results of a query in the order I send it.
So if I write:
SELECT * FROM table WHERE column in (9,1,8)
I would like it to give me the results in the order: 9,1,8
One method uses left join:
select t.*
from (select 9 as c, 1 as priority union all select 1, 2 union all select 8, 3
) vals left join
table t
on t.column = vals.c
order by vals.priority;
Note: This is generic syntax. The specific syntax for the subquery may differ depending on the database.
Another method uses case in the order by:
select t.*
from table t
where t.column in (9, 1, 8)
order by (case column when 9 then 1 when 1 then 2 when 8 then 3 end);
Once again, this can be simplified in some databases, say by using special functions.
You could use CASE expression in order you want, something like:
select *
from table_name
where column_name in (9,1,8)
order by case column_name
when 9 then 1
when 1 then 2
when 8 then 3 end
, column_name -- optional, but here could go another column if you want to have custom order
You can do in Oracle SQL if you have
SELECT Column_name
FROM user_tab_columns
where table_name = 'MY_TABLE'
and Column_id in (9,1,8)
SELECT *
FROM table
WHERE column IN (9, 1, 8)
ORDER BY CASE WHEN column = 9 THEN 1
WHEN column = 1 THEN 2
WHEN column = 8 THEN 3
END