Query to select that records from the table having particular column value - sql

[Ques description]I am having table of bills ,in this I don't want to show the records which is having Doctyp='BIL'
BILNO DOCTYP
1812B00001 BIL
1812B00001 RCR
ADVN CN
ADVN DA
ADVN RCD
ADVN RCR
ADVN TF
AL1707B00006 BIL
AL1707B00006 RCR
I want my output like
BILNO DOCTYP
ADVN CN
ADVN DA
ADVN RCD
ADVN RCR
ADVN TF

NOT IN is one option:
SQL> with test (bilno, doctyp) as
2 (select 182, 'bil' from dual union all
3 select 182, 'xxy' from dual union all
4 select 111, 'abc' from dual union all
5 select 111, 'zdv' from dual union all
6 select 223, 'bil' from dual union all
7 select 555, 'xzy' from dual
8 )
9 select *
10 from test t
11 where bilno not in (select bilno
12 from test
13 where doctyp = 'bil');
BILNO DOC
---------- ---
111 zdv
111 abc
555 xzy
Another is NOT EXISTS:
SQL> with test (bilno, doctyp) as
2 (select 182, 'bil' from dual union all
3 select 182, 'xxy' from dual union all
4 select 111, 'abc' from dual union all
5 select 111, 'zdv' from dual union all
6 select 223, 'bil' from dual union all
7 select 555, 'xzy' from dual
8 )
9 select *
10 from test t
11 where not exists (select null
12 from test t1
13 where t1.bilno = t.bilno
14 and t1.doctyp = 'bil'
15 );
BILNO DOC
---------- ---
111 zdv
111 abc
555 xzy

Related

Oracle filter groups that contains more than one row condition

I need a SQL query for Oracle that select groups that contains the elements "ABC" and "ANQ"
group X Column Q
-------- ---------
123 ABC
123 AAA
123 ANQ
456 ANQ
456 PKR
579 AAA
579 XYZ
886 ABC
The desired result should be
group X Column Q
-------- ---------
123 ABC
123 AAA
123 ANQ
You can query the table only once by using the analytic COUNT function with conditional aggregation:
SELECT x,
q
FROM (
SELECT x,
q,
COUNT(CASE q WHEN 'ABC' THEN 1 END) OVER (PARTITION BY x) AS num_abc,
COUNT(CASE q WHEN 'ANQ' THEN 1 END) OVER (PARTITION BY x) AS num_anq
FROM table_name
)
WHERE num_abc > 0
AND num_anq > 0;
Which, for the sample data:
CREATE TABLE table_name (X, Q) AS
SELECT 123, 'ABC' FROM DUAL UNION ALL
SELECT 123, 'AAA' FROM DUAL UNION ALL
SELECT 123, 'ANQ' FROM DUAL UNION ALL
SELECT 456, 'ANQ' FROM DUAL UNION ALL
SELECT 456, 'PKR' FROM DUAL UNION ALL
SELECT 579, 'AAA' FROM DUAL UNION ALL
SELECT 579, 'XYZ' FROM DUAL UNION ALL
SELECT 886, 'ABC' FROM DUAL;
Outputs:
X
Q
123
ABC
123
AAA
123
ANQ
fiddle
For example:
Sample data:
SQL> with test (x, q) as
2 (select 123, 'abc' from dual union all
3 select 123, 'aaa' from dual union all
4 select 123, 'anq' from dual union all
5 select 456, 'anq' from dual union all
6 select 456, 'pkr' from dual union all
7 select 579, 'aaa' from dual union all
8 select 579, 'xyz' from dual union all
9 select 886, 'abc' from dual
10 )
Query:
11 select x, q
12 from test a
13 where exists (select null
14 from test b
15 where b.q in ('abc', 'anq')
16 and b.x = a.x
17 group by b.x
18 having count(distinct b.q) = 2
19 );
X Q
---------- ---
123 abc
123 aaa
123 anq
SQL>

SQL logic to fail a check if any of the related customers has failed

I have the requirement to flag the customers Y only when all the related customers have also passed the check.
below are the two tables:
relationship table :
customer_id related_customer
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
11 11
11 22
22 11
22 22
Check table
customer_id check_flag
1 y
2 y
3 n
11 y
22 y
I want output like below:
customer_id paas_fail_flag
1 n
2 n
3 n
11 y
22 y
output justification: since 1,2,3 are related customers and since one of them (3) has n in table 2 , so all the related customers should also have n.
11,22 are related customers and both have y in table 2.so in output both should have y.
You need to join relationship to check and use conditional aggregation:
SELECT r.customer_id,
COALESCE(MAX(CASE WHEN c.check_flag = 'n' THEN c.check_flag END), 'y') paas_fail_flag
FROM relationship r INNER JOIN "check" c
ON c.customer_id = r.related_customer
GROUP BY r.customer_id
ORDER BY r.customer_id
See the demo.
Something like this? Sample data in lines #1 - 40; query begins at line #41:
SQL> WITH
2 -- sample data
3 rel (customer_id, related_customer)
4 AS
5 (SELECT 1, 1 FROM DUAL
6 UNION ALL
7 SELECT 1, 2 FROM DUAL
8 UNION ALL
9 SELECT 1, 3 FROM DUAL
10 UNION ALL
11 SELECT 2, 1 FROM DUAL
12 UNION ALL
13 SELECT 2, 2 FROM DUAL
14 UNION ALL
15 SELECT 2, 3 FROM DUAL
16 UNION ALL
17 SELECT 3, 1 FROM DUAL
18 UNION ALL
19 SELECT 3, 2 FROM DUAL
20 UNION ALL
21 SELECT 3, 3 FROM DUAL
22 UNION ALL
23 SELECT 11, 11 FROM DUAL
24 UNION ALL
25 SELECT 11, 22 FROM DUAL
26 UNION ALL
27 SELECT 22, 11 FROM DUAL
28 UNION ALL
29 SELECT 22, 22 FROM DUAL),
30 chk (customer_id, check_flag)
31 AS
32 (SELECT 1, 'y' FROM DUAL
33 UNION ALL
34 SELECT 2, 'y' FROM DUAL
35 UNION ALL
36 SELECT 3, 'n' FROM DUAL
37 UNION ALL
38 SELECT 11, 'y' FROM DUAL
39 UNION ALL
40 SELECT 22, 'y' FROM DUAL),
41 temp
42 AS
43 -- minimum CHECK_FLAG per customer and related customer
44 ( SELECT r.customer_id, r.related_customer, MIN (c.check_flag) mcf
45 FROM rel r JOIN chk c ON c.customer_id = r.related_customer
46 GROUP BY r.customer_id, r.related_customer)
47 SELECT customer_id, MIN (mcf) flag
48 FROM temp
49 GROUP BY customer_id
50 ORDER BY customer_id;
CUSTOMER_ID FLAG
----------- ----
1 n
2 n
3 n
11 y
22 y
SQL>
Assuming that your relationship data could be sparse, for example:
CREATE TABLE relationship ( customer_id, related_customer ) AS
SELECT 2, 3 FROM DUAL UNION ALL
SELECT 3, 1 FROM DUAL UNION ALL
SELECT 3, 2 FROM DUAL UNION ALL
SELECT 11, 22 FROM DUAL;
CREATE TABLE "CHECK" ( customer_id, check_flag ) AS
SELECT 1, 'y' FROM DUAL UNION ALL
SELECT 2, 'y' FROM DUAL UNION ALL
SELECT 3, 'n' FROM DUAL UNION ALL
SELECT 11, 'y' FROM DUAL UNION ALL
SELECT 22, 'y' FROM DUAL;
(Note: The below query will also work on your dense data, where every relationship combination is enumerated.)
Then you can use a hierarchical query:
SELECT customer_id,
MIN(check_flag) AS check_flag
FROM (
SELECT CONNECT_BY_ROOT(c.customer_id) AS customer_id,
c.check_flag AS check_flag
FROM "CHECK" c
LEFT OUTER JOIN relationship r
ON (r.customer_id = c.customer_id)
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY NOCYCLE
( PRIOR r.related_customer = c.customer_id
OR PRIOR c.customer_id = r.related_customer )
AND PRIOR c.check_flag = 'y'
)
GROUP BY
customer_id
ORDER BY
customer_id
Which outputs:
CUSTOMER_ID
CHECK_FLAG
1
n
2
n
3
n
11
y
22
y
db<>fiddle here

Query to get result from checking condition on two-more column from same table

I have a table below:
RuleID | Code | Value
654 Branch 54
654 MessageType MT103
654 Currency USD
654 SourceSys xyz
<!--Comment-Another set of RuleID data-->
656 Branch 54
656 MessageType MT102
656 Currency INR
--------So ON -------------
<!--Comment-Another set of RuleID data-->
658 Branch 54
658 MessageType MT103
658 Currency INR
Every RuleID will max have 5 to 6 code and thier value.It may have 1 also 2 also. Here for example I have given 2 set values.one for Rule id 654 and other 656.
Now Need a query where I can get all RuleID where Branch = 54 and MessageType=MT102
I tried below:- (But this will obviuos not work)
select RuleID
from MyTable
where (CODE='Branch' and Value='54')
and (CODE='MessageType' and Value='MT102')
Read the Union also but that also will not work here.
Think join should do here, but not getting result.
Expected Result: I want to Query all RuleID where Branch is 54 and MessageType is MT103. So Expected Result is Ruleid-654,658
Use OR.
SELECT RuleID
FROM MyTable
WHERE (CODE = 'Branch' AND Value = '54')
OR (CODE = 'MessageType' AND Value = 'MT102')
Something like this, perhaps?
SQL> WITH test (ruleid, code, VALUE)
2 AS (SELECT 654, 'Branch', '54' FROM DUAL
3 UNION
4 SELECT 654, 'MessageType', 'MT103' FROM DUAL
5 UNION
6 SELECT 654, 'Currency', 'USD' FROM DUAL
7 UNION
8 SELECT 654, 'SourceSys', 'xyz' FROM DUAL
9 UNION
10 --
11 SELECT 656, 'Branch', '54' FROM DUAL
12 UNION
13 SELECT 656, 'MessageType', 'MT102' FROM DUAL
14 UNION
15 SELECT 656, 'Currency', 'INR' FROM DUAL)
16 SELECT ruleid
17 FROM test
18 WHERE ( ( code = 'Branch'
19 AND VALUE = '54')
20 OR ( code = 'MessageType'
21 AND VALUE = 'MT102'))
22 GROUP BY ruleid
23 HAVING COUNT (*) = 2;
RULEID
----------
656
SQL>
You can use intersection
WITH MyTable as
(
SELECT 654 RuleId, 'Branch' code, '54' value FROM DUAL
UNION
SELECT 654, 'MessageType', 'MT103' FROM DUAL
UNION
SELECT 654, 'Currency', 'USD' FROM DUAL
UNION
SELECT 654, 'SourceSys', 'xyz' FROM DUAL
UNION
SELECT 656, 'Branch', '54' FROM DUAL
UNION
SELECT 656, 'MessageType', 'MT102' FROM DUAL
UNION
SELECT 656, 'Currency', 'INR' FROM DUAL
)
select RuleID
from MyTable
where CODE='Branch'
and Value='54'
intersect
select RuleID
from MyTable
where CODE='MessageType'
and Value='MT102'

How to sort alphanumeric String in oracle?

Input is:
Section1
Section2
Section3
Section10
Section11
Section1A
Section1B
Section12
Section11A
Section11B
And I want output like:
Section1
Section1A
Section1B
Section2
Section3
Section10
Section11
Section11A
Section11B
Section12
I tried query :
select section_name
from sections
order by length(section_name),section_name
Assuming that the structure of your strings is fixed, as in your example, this could be a way:
SQL> select x,
2 to_number(regexp_substr(x, '[0-9]+')) numericPart,
3 regexp_substr(x, '([0-9]+)([A-Z])', 1, 1, '', 2) optionalChar
4 from (
5 select 'Section1' x from dual union all
6 select 'Section2' from dual union all
7 select 'Section3' from dual union all
8 select 'Section10' from dual union all
9 select 'Section11' from dual union all
10 select 'Section1A' from dual union all
11 select 'Section1B' from dual union all
12 select 'Section12' from dual union all
13 select 'Section11A' from dual union all
14 select 'Section11B' from dual
15 )
16 order by numericPart,
17 optionalChar nulls first
18 ;
X NUMERICPART OPTIONALCHAR
---------- ----------- ----------------------------------------
Section1 1
Section1A 1 A
Section1B 1 B
Section2 2
Section3 3
Section10 10
Section11 11
Section11A 11 A
Section11B 11 B
Section12 12
Here you first order by the numeric part, treating it as number, and then consider the (optional) character after the number.

Distinct LISTAGG that is inside a subquery in the SELECT list

Here is a minimal working example of what I'm trying to do and what I'm getting:
I have a query as follows:
/*
with tran_party as -- ALL DUMMY DATA ARE IN THESE CTE FOR YOUR REFERENCE
(select 1 tran_party_id, 11 transaction_id, 101 team_id_redirect
from dual
union all
select 2, 11, 101 from dual
union all
select 3, 11, 102 from dual
union all
select 4, 12, 103 from dual
union all
select 5, 12, 103 from dual
union all
select 6, 12, 104 from dual
union all
select 7, 13, 104 from dual
union all
select 8, 13, 105 from dual),
tran as
(select 11 transaction_id, 1001 account_id, 1034.93 amount from dual
union all
select 12, 1001, 2321.89 from dual
union all
select 13, 1002, 3201.47 from dual),
account as
(select 1001 account_id, 111 team_id from dual
union all
select 1002, 112 from dual),
team as
(select 101 team_id, 'UUU' as team_code from dual
union all
select 102, 'VV' from dual
union all
select 103, 'WWW' from dual
union all
select 104, 'XXXXX' from dual
union all
select 105, 'Z' from dual)
-- */
-- The Actual Query
select a.account_id,
t.transaction_id,
(select listagg (tm_redir.team_code, ', ')
within group (order by tm_redir.team_code)
from tran_party tp_redir
inner join team tm_redir
on tp_redir.team_id_redirect = tm_redir.team_id
inner join tran t_redir
on tp_redir.transaction_id = t_redir.transaction_id
where t_redir.account_id = a.account_id
and t_redir.transaction_id != t.transaction_id)
as teams_redirected
from tran t inner join account a on t.account_id = a.account_id;
NOTE: tran_party.team_id_redirect is a foreign key that references team.team_id.
Current output:
ACCOUNT_ID TRANSACTION_ID TEAMS_REDIRECTED
---------- -------------- ----------------
1001 11 WWW, WWW, XXXXX
1001 12 UUU, UUU, VV
1002 13
Expected output:
I want the repeated items in TEAMS_REDIRECTED column to be selected only once, like this:
ACCOUNT_ID TRANSACTION_ID TEAMS_REDIRECTED
---------- -------------- ----------------
1001 11 WWW, XXXXX
1001 12 UUU, VV
1002 13
What I tried:
Instead of selecting from tran_party directly, I wrote an inline view that selects distinct values from tran_party like this:
select a.account_id,
t.transaction_id,
(select listagg (tm_redir.team_code, ', ')
within group (order by tm_redir.team_code)
from (select distinct transaction_id, team_id_redirect -- Note this inline view
from tran_party) tp_redir
inner join team tm_redir
on tp_redir.team_id_redirect = tm_redir.team_id
inner join tran t_redir
on tp_redir.transaction_id = t_redir.transaction_id
where t_redir.account_id = a.account_id
and t_redir.transaction_id != t.transaction_id)
as teams_redirected
from tran t inner join account a on t.account_id = a.account_id;
While this does give me the expected output, when I use this solution in my actual code, it takes about 13 seconds to retrieve just one row. Thus I cannot use what I already tried.
Any help will be appreciated.
The following method gets rid of the in-line view to fetch duplicates, it uses REGEXP_REPLACE and RTRIM on the LISTAGG function to get the distinct result set in the aggregated list. Thus, it won't do more than one scan.
Adding this piece to your code,
RTRIM(REGEXP_REPLACE(listagg (tm_redir.team_code, ',')
WITHIN GROUP (ORDER BY tm_redir.team_code),
'([^,]+)(,\1)+', '\1'),
',')
Modified query-
SQL> with tran_party as -- ALL DUMMY DATA ARE IN THESE CTE FOR YOUR REFERENCE
2 (select 1 tran_party_id, 11 transaction_id, 101 team_id_redirect
3 from dual
4 union all
5 select 2, 11, 101 from dual
6 union all
7 select 3, 11, 102 from dual
8 union all
9 select 4, 12, 103 from dual
10 union all
11 select 5, 12, 103 from dual
12 union all
13 select 6, 12, 104 from dual
14 union all
15 select 7, 13, 104 from dual
16 union all
17 select 8, 13, 105 from dual),
18 tran as
19 (select 11 transaction_id, 1001 account_id, 1034.93 amount from dual
20 union all
21 select 12, 1001, 2321.89 from dual
22 union all
23 select 13, 1002, 3201.47 from dual),
24 account as
25 (select 1001 account_id, 111 team_id from dual
26 union all
27 select 1002, 112 from dual),
28 team as
29 (select 101 team_id, 'UUU' as team_code from dual
30 union all
31 select 102, 'VV' from dual
32 union all
33 select 103, 'WWW' from dual
34 union all
35 select 104, 'XXXXX' from dual
36 union all
37 select 105, 'Z' from dual)
38 -- The Actual Query
39 select a.account_id,
40 t.transaction_id,
41 (SELECT RTRIM(
42 REGEXP_REPLACE(listagg (tm_redir.team_code, ',')
43 WITHIN GROUP (ORDER BY tm_redir.team_code),
44 '([^,]+)(,\1)+', '\1'),
45 ',')
46 from tran_party tp_redir
47 inner join team tm_redir
48 on tp_redir.team_id_redirect = tm_redir.team_id
49 inner join tran t_redir
50 on tp_redir.transaction_id = t_redir.transaction_id
51 where t_redir.account_id = a.account_id
52 and t_redir.transaction_id != t.transaction_id)
53 AS teams_redirected
54 from tran t inner join account a on t.account_id = a.account_id
55 /
ACCOUNT_ID TRANSACTION_ID TEAMS_REDIRECTED
---------- -------------- --------------------
1001 11 WWW,XXXXX
1001 12 UUU,VV
1002 13
SQL>