oracle sqlplus report compute columns - oracle

new to this site, so I may not be formatting things right
I have a SQLPlus report that has a very unique requirement that I can't seem to figure out. What I need to do is based on the total value of a break column display a piece of text that says 'Available' or 'Full'.
Here is what the report looks like:
date column 1 column 2 count
===== ======== ======== =====
1/5/14 ABC ABC 10
DEF DEF 20
****** -----
total 30 - this would be a normal compute when break on date
What I need to do is compare that total count field (30 in this case) and if it is > a hard-coded value (say 20) print 'Full' otherwise 'Available'. I'm open to any suggestions, I don't have to print the 30 if there is a way to substitute the text in its place or print on another line or next to it somewhere (Or even if I can make the label say text I want). Issue I have is applying that compare logic in the sqlplus report itself.
Any ideas would be greatly appreciated.
Many thanks.
Mark

SQLPlus has only basic reporting features. In particular, you can't really customize most of its features like BREAK and COMPUTE SUM.
However, you can use all of SQL features so you can probably customize your SQL to get the result you want. Something like this:
SQL> WITH DATA AS (
2 SELECT DATE '2014-05-01' d, 'ABC' c1, 'ABC' c2, 10 cnt FROM dual UNION ALL
3 SELECT DATE '2014-05-01' d, 'DEF' c1, 'DEF' c2, 20 cnt FROM dual UNION ALL
4 SELECT DATE '2014-06-01' d, 'GHI' c1, 'GHI' c2, 10 cnt FROM dual UNION ALL
5 SELECT DATE '2014-06-01' d, 'JKL' c1, 'JKL' c2, 5 cnt FROM dual
6 )
7 SELECT CASE
8 WHEN GROUPING(c1) = 1 THEN '**Total**'
9 ELSE to_char(d, 'dd/mm/yyyy')
10 END dt,
11 c1, c2, SUM(cnt),
12 CASE
13 WHEN GROUPING(c1) = 1 AND SUM(cnt) > 20 THEN 'Full'
14 WHEN GROUPING(c1) = 1 AND SUM(cnt) <= 20 THEN 'Available'
15 END AVAILABILITY
16 FROM DATA
17 GROUP BY d, ROLLUP ((c1, c2));
DT C1 C2 SUM(CNT) AVAILABILITY
---------- --- --- ---------- ------------
01/05/2014 ABC ABC 10
01/05/2014 DEF DEF 20
**Total** 30 Full
01/06/2014 GHI GHI 10
01/06/2014 JKL JKL 5
**Total** 15 Available
6 rows selected
For further reading: an excellent article about GROUP BY, ROLLUP and CUBE by Rob van Wijk.

Related

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).

Joining based on Sum of amount

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>

select matching string from another table oracle

I have a database (Oracle) Table A with some strings in one of columns, Now I want to get matching records from Table B against each column value of Table A for example,
Table A
Name
-----------
ABC
DEE
GHI
JKL
Table B
Name
-----------
ABC
DEF
GHI
JKL
MNO
PQR
Now i want that each string in Table A must be checked against Table B's column and if some string is found almost identical then it should appear against original Value as per below
Table OutPut
Name Matched
--------|----------
ABC | ABC
DEE | DEF
GHI | GHI
JKL | JKL
I have tried following query
with data as(
SELECT Name FROM TABLE_A UNION ALL
SELECT Name FROM TABLE_B
)
SELECT Name
FROM
(
SELECT t.*,utl_match.edit_distance_similarity(upper(Name),upper('DEE')) eds
FROM data t
ORDER BY eds DESC
)
WHERE rownum = 1
but problem is that using this query i can check only one record at a time and that too against a hard coded string. Is there any way to check whole column from Table A one by one against Table B and produce result in output against each string.
Not too clever (hint: performance issue, but - see if it helps. Might be OK if there aren't too many rows involved.
You need lines 21 onwards.
I set similarity to be greater than 80 - adjust it, if needed (which is very probable, as data you posted is really sample data).
SQL> WITH ta (name)
2 AS (SELECT 'ABC' FROM DUAL
3 UNION ALL
4 SELECT 'DEE' FROM DUAL
5 UNION ALL
6 SELECT 'GHI' FROM DUAL
7 UNION ALL
8 SELECT 'JKL' FROM DUAL),
9 tb (name)
10 AS (SELECT 'ABC' FROM DUAL
11 UNION ALL
12 SELECT 'DEF' FROM DUAL
13 UNION ALL
14 SELECT 'GHI' FROM DUAL
15 UNION ALL
16 SELECT 'JKL' FROM DUAL
17 UNION ALL
18 SELECT 'MNO' FROM DUAL
19 UNION ALL
20 SELECT 'PQR' FROM DUAL)
21 SELECT ta.name,
22 tb.name,
23 UTL_MATCH.jaro_winkler_similarity (ta.name, tb.name) sim
24 FROM ta, tb
25 WHERE UTL_MATCH.jaro_winkler_similarity (ta.name, tb.name) > 80
26 ;
NAM NAM SIM
--- --- ----------
ABC ABC 100
DEE DEF 82
GHI GHI 100
JKL JKL 100
SQL>

oracle sql, counting working hours

I have been trying to find something related but couldn't.
I have an issue that i need to produce an availability percentage of something. I have a table that includes events that are happening, which i managed to count them by the day they are happening, but i am finding issues to count the total number of working hours in a quarter or a year.
when each day of the week has a different weight.
Basically my question is: can i do it without making a table with all dates in that month/year?
An example of the data:
ID DATE duration Environment
1 23/10/15 25 a
2 15/01/15 50 b
3 01/01/15 43 c
8 05/06/14 7 b
It can work for me by a calculated field or just a general query to get the information.
sorry I don't really understand the question but if you want to generate dates using connect by level is an easy way to do it (you could also use the model clause or recursive with) I did it here for just 10 days but you get the idea. I put in your dates as t1 and generated a list of dates (t) and then did a left outer join to put them together.
WITH t AS
(SELECT to_date('01-01-2015', 'mm-dd-yyyy') + level - 1 AS dt,
NULL AS duration
FROM dual
CONNECT BY level < = 10
),
t1 AS
(
SELECT to_date('10/01/15', 'dd-mm-yy') as dt, 50 as duration FROM dual
UNION ALL
SELECT to_date('01/01/15', 'dd-mm-yy'), 43 FROM dual
UNION ALL
SELECT to_date('06/01/15', 'dd-mm-yy'), 43 FROM dual
)
SELECT t.dt,
NVL(NVL(t1.duration, t.duration),0) duration
FROM t,
t1
WHERE t.dt = t1.dt(+)
ORDER BY dt
results
DT Duration
01-JAN-15 43
02-JAN-15 0
03-JAN-15 0
04-JAN-15 0
05-JAN-15 0
06-JAN-15 43
07-JAN-15 0
08-JAN-15 0
09-JAN-15 0
10-JAN-15 50
This was my intention, and the full answer below.
WITH t AS
(SELECT to_date('01-01-2015', 'mm-dd-yyyy') + level - 1 AS dt
FROM dual
CONNECT BY level < =365
),
t1 as
(
SELECT dt,
CASE
WHEN (to_char(TO_DATE( t.dt,'YYYY-MM-DD HH24:MI:SS'),'DY') in ('MON', 'TUE', 'WED', 'THU', 'FRI'))
THEN 14*60
WHEN (to_char(TO_DATE( t.dt,'YYYY-MM-DD HH24:MI:SS'),'DY') in ('SAT'))
THEN 8*60
WHEN (to_char(TO_DATE( t.dt,'YYYY-MM-DD HH24:MI:SS'),'DY') in ('SUN'))
THEN 10*60
ELSE 0 END duration ,
to_char(t.dt,'Q') as quarter
FROM t
)
select to_char(t1.dt,'yyyy'), to_char(t1.dt,'Q'),sum(t1.duration)
from t1
group by
to_char(t1.dt,'yyyy'), to_char(t1.dt,'Q');

Forming a SQL query to compare results across rows

Problem statement:
select all stores name , their status, phone numbers , effective date
whose phone number has been changed from 2003 until present date.
Schema is
store_name,phone number , start_date , status
sample rows
abc 1234 30-DEC-2011 open
abc 3433 04-Jan-2012 close
bbb 4444 30-Jan-2010 open
bbb 4444 31-Jan-2011 open
Output
abc 1234 open 30-DEC-3011 till 3-Jan-2012
abc 3433 close 04-Jan-2012 till date
I am also fine having two rows in output with sorted start date like
abc 1234 30-DEC-2011 open
abc 3433 04-Jan-2012 close
bbb should not be reported as there was no change in phone number. We should report only those stores for which phone number was changed .
Can someone help me with this query on Oracle? I guess by using correlated queries it can be done but I am not sure how can I construct one.
Please note that my table is having around 3154953 records so I also need to make sure that correlated query doesn't lock the table for whole lot of time. Is this even possible with Oracle ?
Thanks!
APC's answer works for me just that I am seeing alot of repetitions in my result.
For input :
select store_name,phone_number,start_date, status where store_name=abc;
returns
STORE_name Phone number start_date STATUS
---------------- ---------------- ----------- ----------
abc 122 18-JAN-2011 open
abc 122 18-JAN-2011 open
abc 122 18-JAN-2011 close
running your query gives me following output.
abc 122 open from 18-JAN-2011 to 17-JAN-2011
abc 122 open from 18-JAN-2011 to 17-JAN-2011
abc 122 close from 18-JAN-2011 to date
Can you explain why and where is the miss?
I'm presuming that this is for Oracle rather than MySQL, as my solution uses a couple of magic tricks which I'm pretty certain are not available in MySQL. The first is the Common Table Expression to get a result set which we can use more than once. The second is the use of the LEAD() analytic function to "predict" values in the next row.
So, here's the query:
with a as ( select store_name
, phone_number
, status
, start_date
, lead (start_date, 1, trunc(sysdate)) over (partition by store_name
order by start_date) as next_date
, lead (phone_number, 1, null) over (partition by store_name
order by start_date) as next_number
from your_table
where start_date >= date '2003-01-01' )
select a.store_name
, a.phone_number
, case when a.next_date != trunc(sysdate) then
a.status||' from '|| a.start_date ||' to '||to_char(a.next_date - 1)
else a.status||' from '||a.start_date ||' to date'
end as status_text
from a
where a.store_name in (
select store_name
from a
where phone_number != next_number)
order by a.store_name, a.start_date
/
And here's its output:
SQL> r
1 with a as ( select store_name
...
22 order by a.store_name, a.start_date
23 /
STORE_NAME PHONE_NUMBER STATUS_TEXT
-------------------- ------------ --------------------------------
abc 1234 open from 30-DEC-11 to 03-JAN-12
abc 3433 close from 04-JAN-12 to date
2 rows selected.
SQL>
As for this remark:
"so I also need to make sure that correlated query doesn't lock the
table for whole lot of time"
Doesn't matter in Oracle, because reads don't block other reads. Nor writes come to that.
It will be something along the lines of
select * from table0 as q0 join
(
select min(date) from table0 as q1 where q1.store_name = q0.store_name
) as q2 on q2.store_name = q0.store_name
left join
(
select max(date) from table0 as q1 where q1.store_name = q0.store_name
) as q3 on q3.store_name = q0.store_name
That's not quite right as I don't have MySQL in front of me but its something along these lines.

Resources