how to count rows based on column values null and not null - oracle

May be this question is a duplicate of another, I already explored couple of similar questions here but I didn't find similar one. Please suggest if you find a link to similar question.
My problem is, I have a table say CLIENTS as below
BRANCH CLNTID ACCNT FACID
------ ---------- ---------- ----------
201 10001 123400 110021
201 10001 123401
201 10001 123402 110023
201 10001 123403
201 10001 123404 110025
201 10001 123405
201 10001 123406 110027
201 10001 123407 110028
so on... many rows.
Now I want to write a query to give output like this
Branch clntid facid_null facid_not_null
201 10001 3 5
I want to find facid colmun count for facid=null and facid !=null for each branch and each clntid.
I wrote the below query but its fetching only one count either facid is null or facid is not null.
select branch,clntid,count(*)
from clnt
where facid is null
group by branch, clntid;
Please help me to find both counts in a single query using GROUP BY and as well as OVER (PARTITION BY ) clauses.
Thanks in advance.
Vivek.

select branch
,clntid
,count(*) as num_rows
,count(facid) as not_nulls
,count(*) - count(facid) as nulls
from clnt
group
by branch
,clntid;

The aggregate function COUNT counts all not null occurrences, so you can simply use count(facid) to count the facid_not_null column and you can use a similar technique and first swap the null and not null for the facid_null column. Here is a working example:
SQL> create table clnt (branch,clntid,accnt,facid)
2 as
3 select 201, 10001, 123400, 110021 from dual union all
4 select 201, 10001, 123401, null from dual union all
5 select 201, 10001, 123402, 110023 from dual union all
6 select 201, 10001, 123403, null from dual union all
7 select 201, 10001, 123404, 110025 from dual union all
8 select 201, 10001, 123405, null from dual union all
9 select 201, 10001, 123406, 110027 from dual union all
10 select 201, 10001, 123407, 110028 from dual
11 /
Table created.
SQL> select branch
2 , clntid
3 , count(case when facid is null then 1 end) facid_null
4 , count(facid) facid_not_null
5 from clnt
6 group by branch
7 , clntid
8 /
BRANCH CLNTID FACID_NULL FACID_NOT_NULL
---------- ---------- ---------- --------------
201 10001 3 5
1 row selected.

Related

How to insert values to newly added column

I am new to oracle thus this question.
There is a table already existed and I have added a new column to it.
There are 5 rows and I do not want to use update table with where clause to insert the values one by one in the new column. Is there a statement like INSERT ALL to insert the values into the new column in one shot ?
Thanks
You can also use something like below which in-effect I would say is multiple update only, wrapped in single statement.
SQL> select * from test_upd;
ID1 ID2
---------- ----------
1
2
3
4
SQL> update test_upd a set a.id2 =
2 (select
3 case
4 when id1=1 then 100
5 when id1=2 then 200
6 when id1=3 then 300
7 else 5000 end
8 from test_upd b
9 where a.id1=b.id1);
4 rows updated.
SQL> select * from test_upd;
ID1 ID2
---------- ----------
1 100
2 200
3 300
4 5000
Use a MERGE statement:
MERGE INTO your_table dst
USING (
SELECT 1 AS id, 'aaa' AS newvalue FROM DUAL UNION ALL
SELECT 2, 'bbb' FROM DUAL UNION ALL
SELECT 3, 'ccc' FROM DUAL UNION ALL
SELECT 4, 'ddd' FROM DUAL UNION ALL
SELECT 5, 'eee' FROM DUAL
) src
ON (dst.id = src.id)
WHEN MATCHED THEN
UPDATE SET value = src.newvalue;
Which, if you have the table:
CREATE TABLE your_table (id, value) AS
SELECT 1, CAST(NULL AS VARCHAR2(3)) FROM DUAL UNION ALL
SELECT 2, NULL FROM DUAL UNION ALL
SELECT 3, NULL FROM DUAL UNION ALL
SELECT 4, NULL FROM DUAL UNION ALL
SELECT 5, NULL FROM DUAL;
Then, after the MERGE, the table contains:
ID
VALUE
1
aaa
2
bbb
3
ccc
4
ddd
5
eee
db<>fiddle here

How to achieve string concatentation of entries in column having same id in Oracle Analytics Cloud Professional Edition?

I have a dataset in which one column is Branch-ID and other one is Branch Manager and it looks as follows in the given url.
dataset
I want to combine the branch managers into one single column based on the branch-id. For example if Bob and Sandra are two different branch-managers but have the same branch id which is branch-id=1, then we should concatenate them together as Bob-Sandra and place them in a separately created column.
I have attached the expected output for the above dataset. expected_output_dataset
I am currently using Oracle Analytics Cloud Professional Version.
I don't know Oracle Analytics, but - if it has anything to do with an Oracle database and its capabilities, then listagg helps.
Sample data in lines #1 - 10; query you might be interested in begins at line #11.
SQL> with test (account_id, branch_id, branch_manager) as
2 (select 1, 123, 'Sandra' from dual union all
3 select 3, 124, 'Martha' from dual union all
4 select 4, 125, 'John' from dual union all
5 select 6, 126, 'Andrew' from dual union all
6 select 7, 126, 'Mathew' from dual union all
7 select 2, 123, 'Michael' from dual union all
8 select 5, 125, 'David' from dual union all
9 select 8, 126, 'Mark' from dual
10 )
11 select a.account_id, a.branch_id, a.branch_manager,
12 b.concatenated_column
13 from test a join (select branch_id,
14 listagg(branch_manager, '-') within group (order by null) concatenated_column
15 from test
16 group by branch_id
17 ) b on b.branch_id = a.branch_id;
ACCOUNT_ID BRANCH_ID BRANCH_ CONCATENATED_COLUMN
---------- ---------- ------- -------------------------
1 123 Sandra Michael-Sandra
3 124 Martha Martha
4 125 John David-John
6 126 Andrew Andrew-Mark-Mathew
7 126 Mathew Andrew-Mark-Mathew
2 123 Michael Michael-Sandra
5 125 David David-John
8 126 Mark Andrew-Mark-Mathew
8 rows selected.
SQL>

how to write query to display two rows in one row from same table with different alias column names using oracle

i need to display two rows from same table with different column names. one as Current columns and other as previous columns. How to display it in one row.
SELECT BILL_ID CUR_BILL_ID, BILL_START_DT CUR_BILL_START_DT, BILL_END_DT CUR_BILL_END_DT, BILL_STATUS_CD CUR_BILL_STATUS_CD, BILL_APPROVED_BY CUR_BILL_APPROVED_BY, BILL_APPROVED_DT CUR_BILL_APPROVED_DT FROM FPM_CB_BILL_DETAILS WHERE BILL_ID = (select max(BILL_ID) from FPM_CB_BILL_DETAILS)
SELECT BILL_ID PRV_BILL_ID, BILL_START_DT PRV_BILL_START_DT, BILL_END_DT PRV_BILL_END_DT, BILL_STATUS_CD PRV_BILL_STATUS_CD, BILL_APPROVED_BY PRV_BILL_APPROVED_BY, BILL_APPROVED_DT PRV_BILL_APPROVED_DT FROM FPM_CB_BILL_DETAILS WHERE BILL_ID = (select max(BILL_ID) from FPM_CB_BILL_DETAILS) - 1
Looks like selfjoin might help.
SQL> with fpm_cb_bill_Details (bill_id, bill_status_cd) as
2 (select 100, 'status A' from dual union all
3 select 101, 'status B' from dual union all
4 select 102, 'statuc C' from dual union all
5 select 103, 'status D' from dual
6 )
7 select a.bill_id curr_bill_id,
8 a.bill_status_cd curr_status,
9 b.bill_id prev_bill_id,
10 b.bill_status_cd prev_status
11 from fpm_cb_bill_details a join fpm_cb_bill_details b on b.bill_id = a.bill_id - 1
12 where a.bill_id = (select max(bill_id) from fpm_cb_bill_details);
CURR_BILL_ID CURR_STA PREV_BILL_ID PREV_STA
------------ -------- ------------ --------
103 status D 102 statuc C
SQL>
You can use lag() analytic function to see the previous row's column values, ordering by bill_id as follows:
FSITJA#db01> with fpm_cb_bill_Details (bill_id, bill_status_cd) as
2 (select 100, 'status A' from dual union all
3 select 101, 'status B' from dual union all
4 select 102, 'statuc C' from dual union all
5 select 103, 'status D' from dual
6 )
7 select d.bill_id curr_bill_id,
8 d.bill_status_cd curr_status,
9 lag(d.bill_id) over (order by d.bill_id) prev_bill_id,
10 lag(d.bill_status_cd) over (order by d.bill_id) prev_status
11 from fpm_cb_bill_Details d;
CURR_BILL_ID CURR_STA PREV_BILL_ID PREV_STA
------------ -------- ------------ --------
100 status A
101 status B 100 status A
102 statuc C 101 status B
103 status D 102 statuc C
Thanks #Littlefoot for the sample table data.

Oracle: Concatenate sequence number for repeated values

My situation similar to this but I just want to create sequence number for repeated values only.
Table: MyTable
-----------------------
ID CODE
1 100
2 100
3 200
4 200
5 200
6 300
Below is my query:
SELECT ID, CODE, (row_number() over (partition by CODE order by ID)) as SEQ from MyTable
And this is my current result:
ID CODE SEQ
1 100 1
2 100 2
3 200 1
4 200 2
5 200 3
6 300 1
But my expected result is:
ID CODE SEQ
1 100 1
2 100 2
3 200 1
4 200 2
5 200 3
6 300
Eventually, I do some coding to modify my current result. But I want to ask is there any way to generate the expected result via query only?
You can add CASE COUNT(1) over (partition by CODE) in your query, see sample query below.
WITH MyTable
as (
select 1 id, 100 code from dual union all
select 2 id, 100 code from dual union all
select 3 id, 200 code from dual union all
select 4 id, 200 code from dual union all
select 5 id, 200 code from dual union all
select 6 id, 300 code from dual)
SELECT ID, CODE, CASE COUNT(1) over (partition by CODE)
WHEN 1 THEN NULL
ELSE row_number() over (partition by CODE order by ID)
END as SEQ
from MyTable;
ID CODE SEQ
---------- ---------- ----------
1 100 1
2 100 2
3 200 1
4 200 2
5 200 3
6 300
6 rows selected

OBIEE Sequence Data by Dimensions

First question here, so please be gentle. I've been a lurker for a long time and figured now's a great time to get involved.
Using Oracle OBIEE 12c, I'm looking to create a running counter in my result dataset for instances of a group of dimensions, which reset if the group starts again. Like this - in the below example the counter would consider Cust ID and Status:
Cust ID, Order ID, Status, Counter
111, 123456, APPROVED, 1
111, 123457, APPROVED, 2
111, 123458, APPROVED, 3
111, 123459, DECLINED, 1
111, 123460, APPROVED, 1
111, 123461, APPROVED, 2
222, 123462, APPROVED, 1
222, 123463, APPROVED, 2
Any ideas? I've tried a combination of case statements and RSUM(), but I can't quite get to what I'm after and I'm looking for a fresh approach.
Thanks
I'm not sure how you want your data ordered, so that will matter. It looks like you are ordering by ORDER ID.
You can use a count with Partitioning. Though this may not work depending on how your data is ordered.
SELECT CUSTID, ORDERID, STATUS, count(*)
over (PARTITION BY CUSTID||STATUS ORDER BY ORDERID ROWS UNBOUNDED PRECEDING) COUNTER
FROM MYTEST;
You can also use LAG to check for row changes, for example:
SELECT CUSTID, ORDERID, STATUS, curr_row, prev_row
,CASE WHEN curr_row != prev_row THEN 'Change' ELSE 'Same Group' END as TRACKER
FROM (
SELECT CUSTID, ORDERID, STATUS, CUSTID||STATUS AS curr_row
,LAG(CUSTID||STATUS) OVER (ORDER BY CUSTID, ORDERID, STATUS) AS prev_row
FROM MYTEST
ORDER BY ORDERID
)
;
The above examples are using this set of test data:
Test Data
You should probably calculate the counter outside of OBIEE as part of the extract/load/transform process.
Here is an approximation using the ROW_NUMBER analytical function in Oracle.
with dataset as (
SELECT 111 AS cust_id,
123456 AS order_id,
'APPROVED' AS status,
1 AS expected_counter
FROM dual
UNION ALL
SELECT 111,123457,'APPROVED',2 FROM dual
UNION ALL
SELECT 111,123458,'APPROVED',3 FROM dual
UNION ALL
SELECT 111,123459,'DECLINED',1 FROM dual
UNION ALL
SELECT 111,123460,'APPROVED',1 FROM dual
UNION ALL
SELECT 111,123461,'APPROVED',2 FROM dual
UNION ALL
SELECT 222,1234562,'APPROVED',1 FROM dual
UNION ALL
SELECT 222,1234563,'APPROVED',2 FROM dual
)
select cust_id,order_id,status,expected_counter,row_number() over (partition by cust_id,status order by order_id asc) as counter from dataset ;
The result is:
cust_id /order_id /status / your_counter / my_counter
111 123456 APPROVED 1 1
111 123457 APPROVED 2 2
111 123458 APPROVED 3 3
111 123460 APPROVED 1 4
111 123461 APPROVED 2 5
111 123459 DECLINED 1 1
222 1234562 APPROVED 1 1
222 1234563 APPROVED 2 2
This example helps you find out that customer 111 has 5 approved orders and 1 that was declined; customer 222 has 2 approved orders. I could not match your exact counter. Hope this helps
In OBIEE analysis column formula syntax that'd be sth like
RCOUNT("Orders"."Status" by "Customers"."Cust ID")

Resources