Filter Alphabets from Oracle table - sql

I have input like :-
Table 1
Table 2
A
4
B
5
C
6
1
X
2
Y
3
Z
And Output muse be
Output
A
B
C
X
Y
Z

One method uses a union followed by a filter:
SELECT val
FROM
(
SELECT col1 AS val FROM yourTable
UNION ALL
SELECT col2 FROM yourTable
) t
WHERE REGEXP_LIKE(val, '^[A-Z]+$')
ORDER BY val;

If data really looks as you put it, a simple option is to use greatest function.
Sample data:
SQL> with test (col1, col2) as
2 (select 'A', '4' from dual union all
3 select 'B', '5' from dual union all
4 select 'C', '6' from dual union all
5 select '1', 'X' from dual union all
6 select '2', 'Y' from dual union all
7 select '3', 'Z' from dual
8 )
Query:
9 select greatest(col1, col2) result
10 from test;
RESULT
----------
A
B
C
X
Y
Z
6 rows selected.
SQL>

Related

SQL query to find duplicates with mismatching another column

Table looks like this:
col1 | col2
A | B
A | B
D | C
D | C
E | F
E | G
what I need, is to extract col1 E.
Already tried couple variants of SELECT DISTINCT or SELECT ..., COUNT(*) with GROUP BY, but can't figure it out.
p.s. DBMS is Oracle
Such as this?
SQL> with test (col1, col2) as
2 (select 'A', 'B' from dual union all
3 select 'A', 'B' from dual union all
4 select 'D', 'C' from dual union all
5 select 'D', 'C' from dual union all
6 select 'E', 'F' from dual union all
7 select 'E', 'G' from dual
8 )
9 select col1
10 from test
11 group by col1
12 having count(distinct col2) > 1;
C
-
E
SQL>

SQL How to align ranges of data points in rows?

Suppose having the data set:
with
data_table(title, x) as (
select 'a', 1 from dual union all
select 'a', 3 from dual union all
select 'a', 4 from dual union all
select 'a', 5 from dual union all
select 'b', 1 from dual union all
select 'b', 2 from dual union all
select 'b', 3 from dual union all
select 'b', 6 from dual
)
select * from data_table;
TITLE | X
-----------
a 1
a 3
a 4
a 5
b 1
b 2
b 3
b 6
Wee see that points related to a and b are different.
How to align values in X column so both groups have the same points, filling the gaps with NULL?
Expected result is:
TITLE | X
-----------
a 1
a NULL
a 3
a 4
a 5
a NULL
b 1
b 2
b 3
b NULL
b NULL
b 6
Straightforward solution I got is
with
data_table(title, x) as (
select 'a', 1 from dual union all
select 'a', 3 from dual union all
select 'a', 4 from dual union all
select 'a', 5 from dual union all
select 'b', 1 from dual union all
select 'b', 2 from dual union all
select 'b', 3 from dual union all
select 'b', 6 from dual
),
all_points(x) AS (
select distinct x from data_table
),
all_titles(title) AS (
select distinct title from data_table
),
aligned_data(title, x) as (
select t.title, p.x from all_points p cross join all_titles t
)
select ad.title, dt.x
from aligned_data ad
left join data_table dt on dt.title = ad.title and dt.x = ad.x
order by ad.title, ad.x;
As wee see cross join in aligned_data definition is bottleneck and can kill performance on valuable data sets.
I wonder if this task could be solved more elegantly. Maybe a trick with window functions can be proposed.

Select values is a row as column values

How can I retrieve values in a row as column values?
Example:
Consider the output of below query as INPUT :
Select 1,2,3,4,5,6,7,8,9,10
from dual;
I need a query that can give below output:
COL1
----
1
2
3
4
5
6
7
8
9
10
SELECT 1 AS "COL1" FROM dual
UNION
SELECT 2 FROM dual
UNION
SELECT 3 FROM dual
UNION
SELECT 4 FROM dual
UNION
SELECT 5 FROM dual
UNION
SELECT 6 FROM dual
UNION
SELECT 7 FROM dual
UNION
SELECT 8 FROM dual
UNION
SELECT 9 FROM dual
UNION
SELECT 10 FROM dual ;
If you want to generate a sequence of numbers in Oracle:
with n as (
select level as n
from dual
connect by level <= 10
)
select *
from n;
Or, if you have 10 columns, you can do an unpivot. An easy way is with union all:
select col1 from t union all
select col2 from t union al
. . .
select col10 from t;

Calculating data point which have Precision of 99%

We have a table which have millions of entry. The table have two columns, now there is correlation between X and Y when X is beyond a value, Y tends to be B (However it is not always true, its a trend not a certainty).
Here i want to find the threshold value for X, i.e(X1) such that at least 99% of the value which are less than X1 are B.
It can be done using code easily. But is there a SQL query which can do the computation.
For the below dataset expected is 6 because below 6 more than 99% is 'B' and there is no bigger value of X for which more than 99% is 'B'. However if I change it to precision of 90% then it will become 12 because if X<12 more than 90% of the values are 'B' and there is no bigger value of X for which it holds true
So we need to find the biggest value X1 such that at least 99% of the value lesser than X1 are 'B'.
X Y
------
2 B
3 B
3 B
4 B
5 B
5 B
5 B
6 G
7 B
7 B
7 B
8 B
8 B
8 B
12 G
12 G
12 G
12 G
12 G
12 G
12 G
12 G
13 G
13 G
13 B
13 G
13 G
13 G
13 G
13 G
14 B
14 G
14 G
Ok, I think this accomplishes what you want to do, but it will not work for the data volume you are mentioning. I'm posting it anyway in case it can help someone else provide an answer.
This may be one of those cases where the most efficient way is to use a cursor with sorted data.
Oracle has some builting functions for correlation analysis but I've never worked with it so I don't know how they work.
select max(x)
from (select x
,y
,num_less
,num_b
,num_b / nullif(num_less,0) as percent_b
from (select x
,y
,(select count(*) from table b where b.x<a.x) as num_less
,(select count(*) from table b where b.x<a.x and b.y = 'B') as num_b
from table a
)
where num_b / nullif(num_less,0) >= 0.99
);
The inner select does the following:
For every value of X
Count the nr of values < X
Count the nr of 'B'
The next SELECT computes the ratio of B's and filter only the rows where the ratio is above the threshold. The outer just picks the max(x) from those remaining rows.
Edit:
The non-scalable part in the above query is the semi-cartesian self-joins.
This is mostly inspired from the previous answer, which had some flaws.
select max(next_x) from
(
select
count(case when y='B' then 1 end) over (order by x) correct,
count(case when y='G' then 1 end) over (order by x) wrong,
lead(x) over (order by x) next_x
from table_name
)
where correct/(correct + wrong) > 0.99
Sample data:
create table table_name(x number, y varchar2(1));
insert into table_name
select 2, 'B' from dual union all
select 3, 'B' from dual union all
select 3, 'B' from dual union all
select 4, 'B' from dual union all
select 5, 'B' from dual union all
select 5, 'B' from dual union all
select 5, 'B' from dual union all
select 6, 'G' from dual union all
select 7, 'B' from dual union all
select 7, 'B' from dual union all
select 7, 'B' from dual union all
select 8, 'B' from dual union all
select 8, 'B' from dual union all
select 8, 'B' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'B' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 14, 'B' from dual union all
select 14, 'G' from dual union all
select 14, 'G' from dual;
Give a try with this and share the results:
Assuming table name as table_name and columns as x and y
with TAB AS (
select (count(x) over (PARTITION BY Y order by x rows between unbounded preceding and current row))/
(COUNT(case when y='B' then 1 end) OVER (PARTITION BY Y)) * 100 CC, x, y
from table_name)
select x,y from (SELECT min(cc) over (partition by y) min_cc, x, cc, y
FROM TAB
where cc >= 99)
where min_cc = cc

How to find a specific pattern in some Access data?

I have ex 17 rows and 2 columns in my tabel. Like this:
ColA ColB
---- ----
X 1
X 2
X 3
X a
Y 1
Y 2
Y a
Z 4
Z 4
Z b
Q 1
Q 2
Q 3
Q a
W 4
W b
W 5
Is there a way to look for a pattern in colB of 1,2,3,a for the same value of ColA?
That would give me at output of X and Q.
Your sample data shows distinct rows. In that case, you can use this GROUP BY query.
SELECT y.ColA
FROM YourTable AS y
WHERE y.ColB In ('1','2','3','a')
GROUP BY y.ColA
HAVING Count(*) = 4;
If your actual data might include duplicate rows, you can start with SELECT DISTINCT in a subquery before applying the GROUP BY.
SELECT sub.ColA
FROM
(
SELECT DISTINCT y.ColA, y.ColB
FROM YourTable AS y
WHERE y.ColB In ('1','2','3','a')
) AS sub
GROUP BY sub.ColA
HAVING Count(*) = 4;
(I've assumed that your table is named [PatternData].)
If you use Allen Browne's ConcatRelated function you can create a query to "string together" all of the [ColB] values for each distinct value of [ColA] like this...
SELECT
ColA,
ConcatRelated("ColB", "PatternData", "ColA=""" & ColA & """" , "ColB", "") AS ColB_values
FROM (SELECT DISTINCT ColA FROM PatternData)
...returning...
ColA ColB_values
---- -----------
Q 123a
W 45b
X 123a
Y 12a
Z 44b
Then you can use the above query as the basis for a query to find the [ColA] values with the desired pattern
SELECT ColA
FROM
(
SELECT
ColA,
ConcatRelated("ColB", "PatternData", "ColA=""" & ColA & """" , "ColB", "") AS ColB_values
FROM (SELECT DISTINCT ColA FROM PatternData)
)
WHERE ColB_values = "123a"
...returning...
ColA
----
Q
X
Below is one possible solution:
WITH
data AS (
SELECT 'X' cola, '1' colb FROM dual
UNION ALL SELECT 'X' cola, '2' FROM dual
UNION ALL SELECT 'X', '3' FROM dual
UNION ALL SELECT 'X', 'a' FROM dual
UNION ALL SELECT 'Y', '1' FROM dual
UNION ALL SELECT 'Y', '2' FROM dual
UNION ALL SELECT 'Y', 'a' FROM dual
UNION ALL SELECT 'Z', '4' FROM dual
UNION ALL SELECT 'Z', '4' FROM dual
UNION ALL SELECT 'Z', 'b' FROM dual
UNION ALL SELECT 'Q', '1' FROM dual
UNION ALL SELECT 'Q', '2' FROM dual
UNION ALL SELECT 'Q', '3' FROM dual
UNION ALL SELECT 'Q', 'a' FROM dual
UNION ALL SELECT 'W', '4' FROM dual
UNION ALL SELECT 'W', '5' FROM dual
UNION ALL SELECT 'W', 'b' FROM dual
),
data_agg AS (
SELECT cola, listagg(colb) WITHIN GROUP (ORDER BY colb) AS agg_colb
FROM data
GROUP BY cola
)
SELECT cola
FROM data_agg da
WHERE EXISTS (SELECT 1
FROM data_agg
WHERE cola != da.cola
AND agg_colb = da.agg_colb
)
;
Edit: ops, for some reason I thought you were using Oracle... Hopefully, you'll be able to modify above query to be able to use it.