Get data by joining table does not work in oracle - oracle

I have 2 tables where I want to join it and gets its data. For ex: Table A consists of Error Code and the description of its code is in Table B.
So the value of Error Code is stored like ,1, ,2, ,1,2 in table A.
tbl_fiber_invalid_trans_data -> Table A
TBL_INVALID_ERROR_DATA -> Table B.
I tried joining like below but the Remarks was all blank
SELECT a.SPAN_ID,MAINTENANCE_ZONE_NAME,a.MAINTENANCE_ZONE_CODE,a.R4G_STATE_NAME,
a.NETWORK_CATEGORY,a.NETWORK_TYPE,a.CONSTRUCTION_METHODOLOGY,
a.INVENTORY_STATUS_CODE,a.OWNERSHIP_TYPE_CODE,a.ROUTE_NAME,a.INTRACITY_LINK_ID ,
a.CALCULATED_LENGTH, REPLACE(a.REMARKS, ',1', '1') as REMARKS
FROM tbl_fiber_invalid_trans_data a
left JOIN TBL_INVALID_ERROR_DATA t
ON a.REMARKS = t.ID;
Let me know where I am wrong. and how to replace all those comma separated values
update
Table:tbl_fiber_invalid_trans_data
Name Null Type
------------------------ ---- ---------------
SPAN_ID NVARCHAR2(100)
MAINTENANCE_ZONE_NAME NVARCHAR2(100)
MAINTENANCE_ZONE_CODE NVARCHAR2(50)
R4G_STATE_NAME NVARCHAR2(50)
STATE_NAME NVARCHAR2(50)
NETWORK_CATEGORY NVARCHAR2(100)
NETWORK_TYPE NVARCHAR2(100)
CONSTRUCTION_METHODOLOGY NVARCHAR2(50)
INVENTORY_STATUS_CODE NVARCHAR2(20)
OWNERSHIP_TYPE_CODE NVARCHAR2(20)
ROUTE_NAME NVARCHAR2(100)
INTRACITY_LINK_ID NVARCHAR2(100)
CALCULATED_LENGTH NUMBER(38,8)
LAST_UPDATED_BY NVARCHAR2(100)
LAST_UPDATED_DATE DATE
REMARKS NVARCHAR2(1000)
Table:TBL_INVALID_ERROR_DATA
Name Null Type
-------- ---- --------------
ID NUMBER(18,8)
ERR_CODE NVARCHAR2(500)
Sample data as followed
Table 1
[![img1][1]][1]
Sample data table 2
[![enter image description here][2]][2]

Here's a simplified example that shows how you can extract integers from a comma separated list (REMARKS in tbl_fiber_invalid_trans_data), and then join that to the error codes list (TBL_INVALID_ERROR_DATA) to get the messages:
WITH codes AS (
SELECT DISTINCT SPAN_ID, REGEXP_SUBSTR(remarks, '\d+', 1, level) AS code
FROM tbl_fiber_invalid_trans_data
CONNECT BY REGEXP_SUBSTR(remarks, '\d+', 1, level) IS NOT NULL
)
SELECT t1.*, t2.err_code
FROM tbl_fiber_invalid_trans_data t1
JOIN codes c ON c.SPAN_ID = t1.SPAN_ID
LEFT JOIN TBL_INVALID_ERROR_DATA t2 ON t2.id = c.code
ORDER BY t1.SPAN_ID
Output (for my simplified demo):
SPAN_ID MAINTENANCE_ZONE_NAME REMARKS ERR_CODE
1 Zone 1 ,1 Span id length too short
2 Zone 2 ,2 Inventory suspended
3 Zone 3 ,1,2 Span id length too short
3 Zone 3 ,1,2 Inventory suspended
4 Zone 4 ,2,1 Span id length too short
4 Zone 4 ,2,1 Inventory suspended
5 Zone 5 null null
If you want all the errors for a zone in one line, you can aggregate them in a second CTE and JOIN to that instead:
WITH codes AS (
SELECT DISTINCT SPAN_ID, REGEXP_SUBSTR(remarks, '\d+', 1, level) AS code
FROM tbl_fiber_invalid_trans_data
CONNECT BY REGEXP_SUBSTR(remarks, '\d+', 1, level) IS NOT NULL
),
msgs AS (
SELECT SPAN_ID, LISTAGG(err_code, ', ') WITHIN GROUP (ORDER BY code) AS err_codes
FROM codes c
LEFT JOIN TBL_INVALID_ERROR_DATA t2 ON t2.id = c.code
GROUP BY SPAN_ID
)
SELECT t1.*, m.err_codes
FROM tbl_fiber_invalid_trans_data t1
JOIN msgs m ON m.SPAN_ID = t1.SPAN_ID
ORDER BY t1.SPAN_ID
Output
SPAN_ID MAINTENANCE_ZONE_NAME REMARKS ERR_CODES
1 Zone 1 ,1 Span id length too short
2 Zone 2 ,2 Inventory suspended
3 Zone 3 ,1,2 Span id length too short, Inventory suspended
4 Zone 4 ,2,1 Span id length too short, Inventory suspended
5 Zone 5 null null
Demo on dbfiddle

You need a join with LIKE as follows:
ON a.REMARKS || ',' like '%,'|| t.ID || ',%';
Update
You must use the following query:
SELECT SPAN_ID,
MAINTENANCE_ZONE_NAME,
MAINTENANCE_ZONE_CODE,
R4G_STATE_NAME,
NETWORK_CATEGORY,
NETWORK_TYPE,
CONSTRUCTION_METHODOLOGY,
INVENTORY_STATUS_CODE,
OWNERSHIP_TYPE_CODE,
ROUTE_NAME,
INTRACITY_LINK_ID,
CALCULATED_LENGTH,
LISTAGG(ID,',') WITHIN GROUP (ORDER BY ID) AS REMARKS,
LISTAGG(ERR_CODE,',') WITHIN GROUP (ORDER BY ID) AS ERR_CODE
FROM
(SELECT DISTINCT A.SPAN_ID,
MAINTENANCE_ZONE_NAME,
A.MAINTENANCE_ZONE_CODE,
A.R4G_STATE_NAME,
A.NETWORK_CATEGORY,
A.NETWORK_TYPE,
A.CONSTRUCTION_METHODOLOGY,
A.INVENTORY_STATUS_CODE,
A.OWNERSHIP_TYPE_CODE,
A.ROUTE_NAME,
A.INTRACITY_LINK_ID,
A.CALCULATED_LENGTH,
T.ID,
T.ERR_CODE
FROM TBL_FIBER_INVALID_TRANS_DATA A
LEFT JOIN TBL_INVALID_ERROR_DATA T
ON A.REMARKS || ',' LIKE '%,' || T.ID || ',%')
GROUP BY SPAN_ID,
MAINTENANCE_ZONE_NAME,
MAINTENANCE_ZONE_CODE,
R4G_STATE_NAME,
NETWORK_CATEGORY,
NETWORK_TYPE,
CONSTRUCTION_METHODOLOGY,
INVENTORY_STATUS_CODE,
OWNERSHIP_TYPE_CODE,
ROUTE_NAME,
INTRACITY_LINK_ID,
CALCULATED_LENGTH

Related

How to generate 18 digit code using cursor based on some conditions in Oracle

I have a table from which I want to generate 18 digit code.
Below is the 18 digit code sample which I want.
R-AP-AP01-SMT-4567
Also for generating the above sample code, here is the data and its logic:
R - Fix value
AP – (2 digit state code from STATE column)
EAST- (From ZONE_NAME column from query below
SMT – (From FORMAT_CODE column from below query)
4567 – (From Store Code column from below query)
SELECT STATE, STORE_CODE, ZONE_NAME FROM TBL_RRSOC_STORE_INFO;
AND
select FORMAT_CODE from TBL_SITE_STORE_FORMAT;
How can it be achieved?
Update
Below is the table description
Table name:- TBL_RRSOC_STORE_INFO
Name Null Type
--------------------------- -------- --------------
RRSOC_ID NOT NULL NUMBER
STORE_CODE NOT NULL NVARCHAR2(55)
STATE NVARCHAR2(55)
SLP_STATE NVARCHAR2(100)
FORMAT_GROUP NVARCHAR2(100)
Table name:- TBL_SITE_STORE_FORMAT
Name Null Type
------------ ---- -------------
ID VARCHAR2(20)
STORE_FORMAT VARCHAR2(100)
ISACTIVE VARCHAR2(3)
FORMAT_GROUP VARCHAR2(100)
FORMAT_CODE VARCHAR2(50)
The way you put it, you'd join those tables somehow (cross join is as good as any other, as you didn't explain it better) and concatenate column values.
Something like this:
SQL> with
2 tbl_rrsoc_store_info (state, store_code, zone_name) as
3 (select 'AP', 'EAST', 'SMT' from dual union all
4 select 'NY', 'WEST', 'XYZ' from dual
5 ),
6 tbl_site_store_format (format_code) as
7 (select 4567 from dual)
8 --
9 select 'R' ||'-'|| r.state ||'-'|| r.store_code ||'-'|| r.zone_name ||'-'|| s.format_code result
10 from tbl_rrsoc_store_info r cross join tbl_site_store_format s;
RESULT
--------------------
R-AP-EAST-SMT-4567
R-NY-WEST-XYZ-4567
SQL>
Function returns a value; you didn't explain how it should look like (which parameters it accepts) so I chose to pass state, presuming it is unique within the table.
Sample data:
SQL> select * From tbl_rrsoc_store_info;
ST STOR ZON
-- ---- ---
AP EAST SMT
NY WEST XYZ
SQL> select * from tbl_site_store_format;
FORMAT_CODE
-----------
4567
Function:
SQL> create or replace function f_test (par_state in varchar2)
2 return varchar2
3 is
4 retval varchar2(18);
5 begin
6 select 'R' ||'-'|| r.state ||'-'|| r.store_code ||'-'|| r.zone_name ||'-'|| s.format_code
7 into retval
8 from tbl_rrsoc_store_info r cross join tbl_site_store_format s
9 where r.state = par_state;
10
11 return retval;
12 end;
13 /
Function created.
Testing:
SQL> select r.state, f_test(r.state) result
2 from tbl_rrsoc_store_info r;
ST RESULT
-- --------------------
AP R-AP-EAST-SMT-4567
NY R-NY-WEST-XYZ-4567
SQL>

ORA-01722 invalid number though types should match

table1 dwh.fct_nc_crm_dims#etl4
Name Null Type
--------------------------- -------- -------------
BAN_KEY NOT NULL NUMBER(9)
CLIENT_NAME VARCHAR2(300)
CLIENT_INN VARCHAR2(40)
EFFECTIVE_DATE NOT NULL DATE
EXPIRATION_DATE DATE
table2 etl.stg_acrm_ban_attr#etl2
Name Null Type
---------------- ---- -------------
SEGMENT_CRM VARCHAR2(150)
BAN_KEY VARCHAR2(32)
table3 evkuzmin_b2b_churn_ban_segment
Name Null Type
----------- ---- -------------
BAN_KEY NUMBER(9)
CLIENT_NAME VARCHAR2(300)
CLIENT_INN VARCHAR2(40)
SEGMENT_CRM VARCHAR2(150)
My query. Here I join first 2 tables on ban_key and insert the result into the third table. The types match, but I still get the error. Why?
INSERT INTO evkuzmin_b2b_churn_ban_segment
SELECT a.ban_key, a.client_name, a.client_inn, b.segment_crm FROM(
SELECT ban_key, client_name, client_inn
FROM(
SELECT ban_key,client_name, client_inn,
ROW_NUMBER() OVER (PARTITION BY ban_key, client_inn ORDER BY effective_date DESC) AS rn
FROM dwh.fct_nc_crm_dims#etl4
WHERE expiration_date >= TO_DATE('01.04.2016','DD.MM.YYYY') OR expiration_date IS NULL --1ST DAY OF REPORTING PERIOD
)
WHERE rn = 1
) a, etl.stg_acrm_ban_attr#etl2 b
WHERE a.ban_key = b.ban_key;
Your ban_key in evkuzmin_b2b_churn_ban_segment(table 3) is a Number as compare to the other two tables(varchar).
your a.ban_key is number and b.ban_key is varchar

How do I optimize my hive query for finding Sum of Count of Records from multiple tables

I’ve to generate a report that will give me the sum of the counts from tables A, B and C for events that have been stored using Hive and my S3 buckets have been partitioned by Organization_id
For eg:
Table A – Has a record for every day John (and other employees) goes to work
Table B – Has a record for every call that John (and other employees) makes or takes at work
Table C – Has a record for every expense that John(and other employees) submits at work
Basically I want a sum of the counts from A, B and C for John (employee_id) in the last month. There should be only one record for every date if there is a record in any of the 3 tables A, B or C (and sum the counts if there is a record for a date in one or more of the tables). So my Output is:
Employee id
Employee Name
Date
Count
123
John
02-Jan-2016
55
123
John
12-Jan-2016
88
123
John
19-Jan-2016
103
The query that I came up with is:
select adcts.employee_name, adcts.employee_id,Total_count as event_count, adcts.event_date
from
(select coalesce(Evts.employee_id,imps.employee_id,AEvts.employee_id) as employee_id
, coalesce(Evts.employee_name,imps.employee_name,AEvts.employee_name) as employee_name
, coalesce(Evts.Event_count,0) + coalesce(Imps.Impression_count,0) + coalesce (AEvts.Event_Count,0)as Total_Count
, coalesce (Evts.event_date,imps.impression_date, AEvts.event_date) as event_date
from
(select employee_id, employee_name, count(*) as Event_count,event_date
from mm_events
where organization_id = 100048
and event_date between '2016-02-01' and '2016-02-04'
group by employee_id, employee_name,event_date) Evts
full outer join
(select employee_id, employee_name, count(*) as Impression_count, impression_date
from mm_impressions
where organization_id = 100048
and impression_date between '2016-02-01' and '2016-02-04'
group by employee_id, employee_name,impression_date) Imps
on Evts.employee_id = Imps.employee_id
full outer join
(select employee_id, employee_name, count(*) as Event_count,event_date
from mm_attributed_events
where organization_id = 100048
and event_date between '2016-02-01' and '2016-02-04'
and event_type = 'click'
group by employee_id, employee_name,event_date) AEvts
on AEvts.employee_id=Evts.employee_id
) adcts
join
(select distinct c.employee_id from default.t1_meta_dmp c
where c.employee_dmp_enabled='inherits'
and c.agency_dmp_enabled = 'inherits'
and c.agency_status='true'
and c.employee_status='true'
and c.organization_id = 100048) cc
on adcts.employee_id=cc.employee_id
order by adcts.employee_id asc
I have 2 questions:
1. Do I have the right query?
2. Because I’m using ‘full outer join’ I get more than one entry for the same date. Can someone suggest a better way to achieve the result? Different query maybe
You are getting more than one entry for the same date because you are grouping by date in subqueries but joining them only by employee_id. That is why your records are duplicated after join. You should add event_date to the join condition as well.
It seems you do not need FULL JOIN at all. Join is more expensive than union all. Use UNION ALL select from each table then group by employee_name, employee_id, event_date and aggregate count() :
select employee_id, employee_name, sum(Event_count) as Total_Count , event_date
from
(
select employee_id, employee_name, count(*) as Event_count, event_date from mm_events
where organization_id = 100048 and event_date between '2016-02-01' and '2016-02-04'
group by employee_id, employee_name, event_date
union all
select employee_id, employee_name, count(*) as Event_count, impression_date as event_date
from mm_impressions
where organization_id = 100048 and impression_date between '2016-02-01' and '2016-02-04'
group by employee_id, employee_name,impression_date
union all
select employee_id, employee_name, count(*) as Event_count,event_date
from mm_attributed_events
where organization_id = 100048 and event_date between '2016-02-01' and '2016-02-04' and event_type = 'click'
group by employee_id, employee_name, event_date
) adcts
group by employee_id, employee_name, event_date
Add your join with cc query to the above query.
All subqueries in UNION ALL will run in parallel

How to bind horizontal values of a table to a vertical values of another table in oracle database

i have 2 tables .
The columns start with attributes are change based on department. the description of attributes are here
My requirement is to get the values of each attributes with its primary key based on the department as table bellow.
Honestly i am stuck on this problem in my program. I have no permission to change the tables and there is no common unique key column.i would appreciate if anyone could provide me a suggestion.
with a as (
select a.*, row_number() over (partition by department order by attributeID) rn
from attributes a),
e as (
select employeeId, department, attribute1, 1 rn from employees union all
select employeeId, department, attribute2, 2 rn from employees union all
select employeeId, department, attribute3, 3 rn from employees
)
select e.employeeId, a.attributeid, e.department, a.attribute, a.meaning,
e.attribute1 as value
from e join a on a.department=e.department and a.rn=e.rn
order by e.employeeId, a.attributeid
Test data and output:
create table employees (employeeID number(3), name varchar2(10), department varchar2(5), age number(3), attribute1 varchar2(10), attribute2 varchar2(10), attribute3 varchar2(10));
insert into employees values (1, 'john', 'IT', 22, 'attr1val1', 'attr2val2', null);
insert into employees values (2, 'jane', 'HR', 32, 'attr1val3', 'attr2val4', 'attr3val5');
insert into employees values (3, 'joe', 'HR', 23, 'attr1val6', 'attr2val7', 'attr3val8');
insert into employees values (4, 'jack', 'IT', 45, 'attr1val9', 'attr2val10', null);
create table attributes (attributeID number(3), department varchar2(10), attribute varchar2(10), meaning varchar2(10));
insert into attributes values (1, 'IT', 'attribute1', 'laptoptype');
insert into attributes values (2, 'IT', 'attribute2', 'networkloc');
insert into attributes values (3, 'HR', 'attribute1', 'location');
insert into attributes values (4, 'HR', 'attribute2', 'position');
insert into attributes values (5, 'HR', 'attribute3', 'allocation');
EMPLOYEEID ATTRIBUTEID DEPARTMENT ATTRIBUTE MEANING VALUE
---------- ----------- ---------- ---------- ---------- ----------
1 1 IT attribute1 laptoptype attr1val1
1 2 IT attribute2 networkloc attr2val2
2 3 HR attribute1 location attr1val3
2 4 HR attribute2 position attr2val4
2 5 HR attribute3 allocation attr3val5
3 3 HR attribute1 location attr1val6
3 4 HR attribute2 position attr2val7
3 5 HR attribute3 allocation attr3val8
4 1 IT attribute1 laptoptype attr1val9
4 2 IT attribute2 networkloc attr2val10
Edit: Explanation
In answer I used with
clause just to divide solution into readable steps. You can move them into from clause of main query if it is
more comfortable for you. Anyway: subquery a reads data from table attributes and adds number for rows,
so for each department they are allways numbered from 1. I used row_number() for that. Subquery e unions (all) required attributes and numbers
them accordingly. Numbers generated in both subqueries are then used in main join: a.department=e.department and a.rn=e.rn.
Alternative 1 - if you are using Oracle 11g you could use the unpivot. See what is generated by subquery, and how it is joined with attributes table:
with e as (
select employeeId, name, department, attribute, value from employees
unpivot (value for attribute in ("ATTRIBUTE1", "ATTRIBUTE2", "ATTRIBUTE3"))
)
select e.employeeId, a.attributeid, e.department, a.attribute,
a.meaning, e.value
from e join attributes a on a.department=e.department
and lower(a.attribute)=lower(e.attribute)
order by e.employeeId, a.attributeid;
Alternative 2 - with hierarchical subquery generator (subquery r), realised by connect by which simple creates numbers from 1, 2, 3 which are next joined with employees and proper attribute
is attached as value in case clause. Rest is made in similiar way like in original answer.
with a as (
select a.*, row_number() over (partition by department order by attributeID) rn
from attributes a),
r as (select level rn from dual connect by level<=3),
e as (
select employeeId, department, rn,
case when r.rn = 1 then attribute1
when r.rn = 2 then attribute2
when r.rn = 3 then attribute3
end value
from employees cross join r
)
select e.employeeId, a.attributeid, e.department, a.attribute,
a.meaning, e.value
from e join a on a.department=e.department and a.rn=e.rn
order by e.employeeId, a.attributeid
All three versions gave me the same output. I also tested first option on similiar table with 100k rows and get output in few seconds (for 5 attributes). Please test all solutions and try to understand them. If you can use unpivot version I would prefer this.
Sorry for delayed explanation and any language mistakes.
The WITH clause was added with Oracle 9.2 and should do the trick. For the other attributes just add more sub queries where the filter is att.attribute = 'attribute2' or 'Attribute3'...
WITH e AS
(SELECT emp.employee_ID, emp.department, emp.attribute1
FROM employee emp),
a AS (SELECT att.attribute_id, att.attribute, att.meaning
FROM attribute_TYPE att
WHERE att.attribute = 'attribute1')a
SELECT e.employeeid, att.attributeid, e.department, a.attribute,
a.meaning e.attribute1
FROM e JOIN a ON e.department = a.department

How to display comma separated descriptions based on comma separated values in Oracle 10g?

I am new to Oracle technology. Earlier I posted 2 posts for the same issue due to lack of understanding the requirement.
Table 1:
MSGID
-----
1,2,3
2,3
4
null
null
Table 2:
MID MSGDESC
---- -------
1 ONE
2 TWO
3 THREE
4 FOUR
Expected output:
XCOL DESC
----- -----
1,2,3 ONE,TWO,THREE
2,3 TWO,THREE
4 FOUR
I am not able to fulfil this requirement. Please provide me one solution.
Note: tables don't have any unique or primary key values. Table 1 has 5000 records and table 2 only has 80 records with descriptions.
create table Table1 (MSGID varchar2(100));
insert into Table1 values ('1,2,3');
insert into Table1 values ('2,3');
insert into Table1 values ('4');
insert into Table1 values (null);
insert into Table1 values (null);
create table Table2 (MID varchar2(100), MSGDESC varchar2(100));
insert into Table2 values ('1','ONE');
insert into Table2 values ('2','TWO');
insert into Table2 values ('3','THREE');
insert into Table2 values ('4','FOUR');
select
msgid as xcol,
"DESC",
col1, col2, ..., col12
from
Table1
left join (
select
msgid,
wm_concat(msgdesc) as "DESC"
from
(
select
msgid,
msgdesc
from
(select distinct msgid from Table1 where ...)
cross join (
select level as occ from dual connect by level <= 100)
)
left join Table2
on mid = regexp_substr(msgid, '[^,]+', 1, occ)
where
occ <= regexp_count(msgid, ',') + 1
order by msgid, occ
)
group by msgid
) using (msgid)

Resources