Joining based on Sum of amount - oracle

Basically there are 2 files
File 1 sample
Reference
Amount
AA1
1000
File 2 sample
Reference
Match_No
Side
Amount
AA1
123
Ledger
1000
BB1
123
Statement
500
CC1
123
Statement
500
Now the requirement is using the reference from File 1 extract the Match_No from file 2 where side = 'Ledger'
The script I think for this should be:-
select file2.match_no
from file1 join file2 on file1.reference = file2.reference
where side = 'Ledger'
Now after extracting Match_No where side = Ledger, for the same Match_No extract all the references from file 2 where side ='Statement' and sum of file2.amounts (where side='Statement') = file2.amount(where side = Ledger)

This is how I understood what you are saying. See if it helps.
SQL> with
2 -- Sample data; you have it already & don't type it
3 file_1 (reference, amount) as
4 (select 'aa1', 1000 from dual),
5 file_2 (reference, match_no, side, amount) as
6 (select 'aa1', 123, 'Ledger' , 1000 from dual union all
7 select 'bb1', 123, 'Statement', 500 from dual union all
8 select 'cc1', 123, 'Statement', 500 from dual
9 ),
10 -- Useful code begins here.
11 -- Query you posted (I added "B.AMOUNT" and used it in line #21)
12 qyp as
13 (select b.match_no, b.amount
14 from file_1 a join file_2 b on a.reference = b.reference
15 where b.side = 'Ledger'
16 )
17 -- The final query
18 select b.reference
19 from file_2 b join qyp q on q.match_no = b.match_no
20 where b.side = 'Statement'
21 and q.amount = (select sum(c.amount)
22 from file_2 c
23 where c.match_no = b.match_no
24 and c.side = 'Statement'
25 );
REF
---
cc1
bb1
SQL>

Related

Oracle Subquery while using count and max with join

Table COMPUTER:
Table SUPPLIER:
how to display the building location that has the most computers?
i Have been trying several ways include subquery, joins, max, count but all not working and error keeps happending
The result i pursueing is
SUPPID SNAME SADDRESS MAKE COUNT(*)
125 Apple Sdn.Bhd 18 Jalan Duta Apple 3
For example (where sample data is in lines #1 - 12; query you might be interested in begins at line #13):
SQL> with
2 -- sample data
3 computer (compid, make, suppid, locid) as
4 (select 13323, 'IBM' , 124, 333 from dual union all
5 select 13324, 'Apple', 125, 444 from dual union all
6 select 13325, 'Apple', 125, 444 from dual union all
7 select 13326, 'Apple', 125, 444 from dual
8 ),
9 supplier (suppid, sname, saddress) as
10 (select 124, 'IBM Sdn.Bhd' , '15 Jalan Duta' from dual union all
11 select 125, 'Apple Sdn.Bhd', '18 Jalan Duta' from dual
12 ),
13 comp_loc as
14 -- number of computers per location; RNK = 1 shows location with most computers
15 (select locid,
16 rank() over (order by count(*) desc) rnk,
17 count(*) cnt
18 from computer
19 group by locid
20 )
21 select distinct s.suppid, s.sname, s.saddress, c.make, l.cnt
22 from supplier s join computer c on c.suppid = s.suppid
23 join comp_loc l on l.locid = c.locid
24 where l.rnk = 1;
SUPPID SNAME SADDRESS MAKE CNT
---------- ------------- ------------- ----- ----------
125 Apple Sdn.Bhd 18 Jalan Duta Apple 3
SQL>
On Oracle 12 and newer
select s.suppid, s.sname, s.saddress, c.make, count(1)
from COMPUTER c
join SUPPLIER s
on c.suppid = s.suppid
group by s.suppid, s.sname, s.saddress, c.make
order by count(1) desc
fetch first 1 row only <-- this line will fetch you the top 1 line only
You might also use "fetch first 1 row with ties" to output all the top manufacturers if there are many of them having same "count". E.g If IBM and Appl were having same amount of lines
On Oracle version before 12 do the following:
select *
from (select s.suppid, s.sname, s.saddress, c.make, count(1)
from comps c
join suppls s
on c.suppid = s.suppid
group by s.suppid, s.sname, s.saddress, c.make
order by count(1) desc)
where rownum = 1; <-- this line will get you the top 1 manufacturer only
PS. version of the oracle database can be obtained for example using:
select version from v$instance;

search in text using subtext in Oracle PLSQL

I have this query in master_t table that hold ration_category column and many number of sectors in sectors column like this 'BN:INS' or 'BN' or 'BN:IM:INS' etc..
select distinct ratio_category d from master_t
where status = 'Y' and (SECTORS = :P23_SECTORS or
(INSTR(':'||:SECTORS ||':',:P23_SECTORS)>0 OR UPPER(:P23_SECTORS) = 'ALL')) order by ratio_category
P23_SECTORS= 'BN:INS'
SECTORS='INS:MFI:SB:BN'
: is a separator of multi data
I need to check if data inside P23_sectors are exists in SECTORS variable ,
but this query doesn't get data because the multi data separator
Is there anyway to adjust the query so I could compare subtext with full text
note : the order is different.
Expected output :
LL
PP
CC
Thanks
Here's one option (read comments within code):
SQL> with master_t (ratio_category, sectors) as
2 -- sample data
3 (select 1, 'INS:MFI:SB:BN' from dual union all
4 select 2, 'BN:LF' from dual
5 ),
6 split_t as
7 -- split SECTORS into rows
8 (select ratio_category,
9 sectors,
10 regexp_substr(sectors, '[^:]+', 1, column_value) sec
11 from master_t cross join
12 table(cast(multiset(select level from dual
13 connect by level <= regexp_count(sectors, ':') + 1
14 ) as sys.odcinumberlist))
15 ),
16 split_23 as
17 -- split P23_SECTORS into rows
18 (select regexp_substr('&&P23_SECTORS', '[^:]+', 1, level) sec,
19 regexp_count('&&P23_SECTORS', ':') + 1 cnt
20 from dual
21 connect by level <= regexp_count('&&P23_SECTORS', ':') + 1
22 )
23 -- return rows that contain complete P23_SECTORS value(s)
24 select t.ratio_category, t.sectors
25 from split_t t join split_23 s on s.sec = t.sec
26 group by t.ratio_category, t.sectors
27 having count(*) = max(s.cnt);
Enter value for p23_sectors: BN:INS
RATIO_CATEGORY SECTORS
-------------- -------------
1 INS:MFI:SB:BN
SQL>
Pay attention to comments people posted. They do have serious experience with programming and you'd rather listen to what they say and thank them for spending time to check your problem. Your reply to Ed is rather rude; if I were Ed, I'd make sure not to respond to any of your future questions (read: I'd let you solve your own problems).

How to find text fields that contains a list of words

I'm using Oracle PLSQL.
I want to return TextFields that contains a list of words (with 'and' operator between them).
The result string must contain all the words provided from the user, the order is not importent.
Example:
param_col varchar2(100):= 'Project|Data|Book';
(The list of words are unknown, depend on user parameter)
TextField:
1.'The Project will contain Data from Book'
2.'The Project Data is not valid.
3.'Project is the best data Book exists'
Expected Result:
1.'The Project will contain Data from Book'
3.'Project is the best data Book exists'
Here's one option. See comments within code.
SQL> with
2 test (id, col) as
3 -- Test sample data
4 (select 1, 'The Project will contain Data from Book' from dual union all
5 select 2, 'The Project Data is not valid' from dual union all
6 select 3, 'Project is the best data Book exists' from dual
7 ),
8 param (par) as
9 -- input parameter
10 (select 'Project|Data|Book' from dual),
11 --
12 spltest as
13 -- split TEST sentences to words
14 (select id,
15 lower(regexp_substr(col, '[^ ]+', 1, column_value)) val
16 from test cross join table(cast(multiset(select level from dual
17 connect by level <= regexp_count(col, ' ') + 1
18 ) as sys.odcinumberlist))
19 ),
20 splpar as
21 -- split PARAMETER into words; include IDs from TEST
22 (select t.id,
23 lower(regexp_substr(p.par, '[^\|]+', 1, column_value)) val
24 from param p cross join test t
25 cross join table(cast(multiset(select level from dual
26 connect by level <= regexp_count(p.par, '\|') + 1
27 ) as sys.odcinumberlist))
28 )
29 -- final result: select rows from the TEST table ...
30 select t.id, t.col
31 from test t
32 -- ... where ID is contained in intersected set of values from SPLTEST and SPLPAR ...
33 where t.id in (select x.id from (select t1.id, t1.val from spltest t1
34 intersect
35 select p.id, p.val from splpar p
36 ) x
37 group by x.id
38 -- ... while that "intersected set" has to contain all values from the PARAM
39 having count(*) = (select regexp_count(p1.par, '\|') + 1
40 from param p1
41 )
42 );
ID COL
---------- ---------------------------------------
1 The Project will contain Data from Book
3 Project is the best data Book exists
SQL>

How to return non-empty rows for a given ID - Hive

I have a table X
ID A B
--------------
1 abc 27
1 - 28
2 - 33
3 xyz 41
3 - 07
I need output as
ID A B
--------------
1 abc 27
2 - 33
3 xyz 41
I tried doing
max(A) OVER (PARTITION BY ID) as the_value
but it did not work. I can still see all the rows in the output table.
I was wondering if somebody has come across a similar situation and has a solution to this ?
you can use this simple trick for getting the full record for which some column is maxed:
select original.* from
(select ID,max(B) as B from Tbl group by ID ) maxB
inner join
(select * from Tbl ) original
on original.ID = maxB.ID and original.B = maxB.B
now this is of course an overkill code. you can also do:
select Tbl.* from
(select ID,max(B) as B from Tbl group by ID ) maxB
inner join
Tbl
on Tbl.ID = maxB.ID and Tbl.B = maxB.B
but the first version is more of a template to do whatever you want with further columns, fields, conditions joins etc.

Max size in a connected by prior Oracle

I've got some help turning my table of the sort:
Col
23
25
15
53
...
into something like 23,25,15,53...
The query that does it is
SELECT max(ltrim(sys_connect_by_path(flow_run_id, ','), ','))
FROM
(select flow_run_id, rownum rn
from table
where CREATED_DATE < sysdate - 32
and flow_id = 3
order by 1 desc)
START WITH rn = 1
CONNECT BY PRIOR rn = rn - 1
(this beaulty was given by Michael in here)
My current problem is that the result is too long (ORA-01489 over the 4k chars from varchar2). I'm still learning about these sys_connected_by_path so I'd need some help sorting this. How could I make this query return me multiple rows instead of one super long line? i.e.:
Instead of
419,1,2,3,411,418,4,415,887,413,414,201,888,890,401,417,610,412,416,5,6,922,1080,1422,1423,1411,1412,1413,1414,1415,1416,1417,1418,1419,1964,2217,1636,2037,1988,1970,2038,1989,2000,2040,1993,2043,1994,2001,2044,1658,1995,2045,2224,1996,2019,1678,1997,2022,2201,1680,2219,2024,2207,1677,2209,2220,1959,2211,1961,2026,2212,1962,2028,2215,1675,1676,2035,2216,1986,1963,2017,1983,1935,2002,2018,1985,1936,2003,2020,2032,1937,2004,2021,2033,1938,1943,2023,2034,1939,1944,2025,2225,1941,1950,2027,2036,1942,1955,2029,2041,1945,1956,2030,2227,1946,1957,2031,2039,1947,2005,1974,2042,1948,2006,1976,2228,1949,2007,1978,1951,2009,1979,1929,1952,2012,1980,1931,1953,2013,1981,1933,1954,2015,2334,2350,2311,2239,2240,2241,2242,2245,2246,2249,2250,2336,2312,2008,2010,2011,2014,2251,2253,2016,2243,2244,2247,2351,2248,(...)
get
419,1,2,3,411,418,4,415,887,413,414,201,888,890,401,417,610,412,416,5,6,922,1080
1423,1411,1412,1413,1414,1415,1416,1417,1418,1419,1964,2217,1636,2037,1988,1970,2038
2000,2040,1993,2043,1994,2001,2044,1658,1995,2045,2224,1996,2019,1678,1997,2022,2201
(...)
Any tips?
Thanks!
f.
the following query will cut your big string in parts:
SQL> SELECT root_rn, MAX(concat)
2 FROM (SELECT connect_by_root(rn) root_rn,
3 ltrim(sys_connect_by_path(flow_run_id, ','), ',') concat
4 FROM (SELECT flow_run_id, rownum rn
5 FROM (SELECT round(dbms_random.VALUE(1, 10000))
6 AS flow_run_id
7 FROM dual
8 CONNECT BY ROWNUM <= 2000)
9 ORDER BY 1 DESC)
10 START WITH MOD(rn, 10) = 1
11 CONNECT BY PRIOR rn = rn - 1
12 AND MOD(rn, 10) != 1)
13 GROUP BY root_rn
14 ORDER BY root_rn;
ROOT_RN MAX(CONCAT)
---------- -------------------------------------------------------------------
1 654,6710,5297,5481,5085,2793,7646,9170,1051,2387
11 1882,8285,5430,4928,267,3779,3843,1151,3085,1446
21 4721,6087,6755,9904,805,2776,4633,2772,7785,5818
31 5189,5307,6481,2099,3832,9788,5970,8068,6605,3904
41 53,7013,1314,7717,9320,7069,907,5367,5013,7637
51 3903,2318,2611,7954,5751,5598,6148,6555,9724,984
[...]
You can replace "10" with a bigger number if you want more elements on each row.
Some little modifications to keep order
SELECT 10*frn+1 root,ltrim(sys_connect_by_path(flow_run_id,','),',') FROM
(SELECT flow_run_id,mod(rn,10) mrn,floor(rn/10) frn,count(*)over(partition by floor(rn/10))-1 crn FROM
(SELECT flow_run_id, row_number()over(order by flow_run_id)-1 rn FROM
(SELECT round(dbms_random.VALUE(1, 10000)) AS flow_run_id FROM dual CONNECT BY ROWNUM <= 2000
)
)
)
WHERE crn = mrn
START WITH mrn = 0
CONNECT BY PRIOR mrn = mrn-1 AND PRIOR frn = frn

Resources