How to append result from select to resultset? - oracle

I have the following tables:
Table 1 - NODES (I access it through a DB_LINK):
SITE_ID LATITUDE LONGITUDE
ABC123 21.018 -89.711
CDE456 20.35 -87.349
FGH789 20.258 -87.406
ABB987 18.54 -88.302
CFF546 18.542 -88.273
GHT553 18.52 -88.311
Table 2 - LINKS
ID SITE_A SITE_B STATUS NAME LINK_TYPE REGION ---> Many other fields
1 ABC123 GHT553
2 FGH789 CFF546
3 CDE456 ABC123
4 CFF546 GHT553
Table 3 - RESULT (This is what I want to achieve) - No matter the order
LINK_ID SITE_A_ID LAT_SITE_A LON_SITE_A SITE_B_ID LAT_SITE_B LON_SITE_B
1 ABC123 21.018 -89.711 GHT553 18.52 -88.311
2 FGH789 20.258 -87.406 CFF546 18.542 -88.273
3 CDE456 20.35 -87.349 ABC123 21.018 -89.711
4 CFF546 18.542 -88.273 GHT553 18.52 -88.311
(Plus several other fields, which means no trouble for me)
This is what I have tried:
SELECT RES2.*, SAM2.LATITUDE LAT_SITE_B, SAM2.LONGITUDE LON_SITE_B FROM(
SELECT RES1.*, NOD.LATITUDE LAT_SITE_A, NOD.LONGITUDE LON_SITE_A FROM(
SELECT ID, SITE_A, SITE_B, STATUS, NAME, LINK_TYPE FROM LINKS
WHERE SITE_A IS NOT NULL AND SITE_B IS NOT NULL AND REGION IN (8,6)
)RES1, NODES#NODES_DBLINK NOD WHERE RES1.SITE_A = NOD.SITE_ID
)RES2, NODES#NODES_DBLINK NOD2
WHERE RES2.SITE_B = NOD2.SITE_ID;
Until the SELECT RES1.\*, everything works fine, but when I add the SELECT RES2.\*, it takes too long without returning anything.

From the textual part of your question, this query will generate the result you want:
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN nodes#nodes_dblink node_a ON (links.site_a = node_a.site_id)
INNER JOIN nodes#nodes_dblink node_b ON (links.site_b = node_b.site_id)
ORDER BY links.id;
From the query you posted it seems you have some other criteria to include too which might mean you want something more like this:
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN nodes#nodes_dblink node_a ON (links.site_a = node_a.site_id)
INNER JOIN nodes#nodes_dblink node_b ON (links.site_b = node_b.site_id)
WHERE links.site_a IS NOT NULL
AND links.site_b IS NOT NULL
AND links.region IN (8, 6)
ORDER BY links.id;
Hope it helps...
EDIT:
If your DB link is an issue, try to return only the data you're going to need over the link in advance either by creating a view on the remote DB or a materialised view on the local DB.
If that isn't practical then check the relative explain plans for the query above against this one and see if it is any better:
WITH node_data
AS (SELECT site_id,
latitude,
longitude
FROM nodes#nodes_dblink node
WHERE EXISTS (SELECT 1
FROM links
WHERE links.site_a = node.site_id
OR links.site_b = node.site_id))
SELECT links.id AS link_id,
node_a.site_id AS site_a_id,
node_a.latitude AS lat_site_a,
node_a.longitude AS lon_site_a,
node_b.site_id AS site_b_id,
node_b.latitude AS lat_site_b,
node_b.longitude AS lon_site_b
FROM links
INNER JOIN node_data node_a ON (links.site_a = node_a.site_id)
INNER JOIN node_data node_b ON (links.site_b = node_b.site_id)
WHERE links.site_a IS NOT NULL
AND links.site_b IS NOT NULL
AND links.region IN (8, 6)
ORDER BY links.id;

Related

Joining 3 tables doesnt work, should I use a subquery for the below

I have this query.
SELECT re_current_benefits.prospect_nbr, qo_quote.quote_id, hra_ind, quote_type, effective_date, quote_expiration_ind, mhs_lob_code
FROM re_current_benefits
INNER JOIN qo_quote ON qo_quote.prospect_nbr = re_current_benefits.prospect_nbr
WHERE hra_ind = 'Y' AND quote_type = 'R' AND quote_expiration_ind IS NULL AND mhs_lob_code NOT IN 'DTL1' AND mhs_lob_code NOT IN 'DTL2'
And I need to pull the prospect_nbr from here, I also need to add a filter saying effective_date = renewal_date but if I do that by joining all 3 tables together I get 0 results which should not be the case.
SELECT prospect_nbr, rmr_run_status, renewal_date
FROM re_group
WHERE rmr_run_status = ANY ('S', 'W')

Oracle Performance issues on using subquery in an "In" orperator

I have two query that looks close to the same but Oracle have very different performance.
Query A
Create Table T1 as Select * from FinalView1 where CustomerID in ('A0000001','A000002')
Query B
Create Table T1 as Select * from FinalView1 where CustomerID in (select distinct CustomerID from CriteriaTable)
The CriteriaTable have 800 rows but all belongs to Customer ID 'A0000001' and 'A000002'.
This means the subquery: "select distinct CustomerID from CriteriaTable" also only returns the same two elements('A0000001','A000002') as manually entered in query A
Following is the query under the FinalView1
create or replace view FinalView1_20200716 as
select
Customer_ID,
<Some columns>
from
Table1_20200716 T1
INNER join Table2_20200716 T2 on
T1.Invoice_number = T2.Invoice_number
and
T1.line_id = T2.line_id
left join Table3_20200716 T3 on
T3.id = T1.Customer_ID
left join Table4_20200716 T4 on
T4.Shipping_ID = T1.Shipping_ID
left join Table5_20200716 Table5 on
Table5.Invoice_ID = T1.Invoice_ID
left join Table6_20200716 T6 on
T6.Shipping_ID = T4.Shipping_ID
left join First_Order first on
first.Shipping_ID = T1.Shipping_ID
;
Table1_20200716,Table2_20200716,Table3_20200716,Table4_20200716,Table5_20200716,Table6_20200716 are views to the corresponding table with temporal validity feature. For example
The query under Table1_20200716
Create or replace view Table1_20200716 as
select
*
from Table1 as for period of to_date('20200716,'yyyymmdd')
However table "First_Order" is just a normal table as
Following is the performance for both queries (According to explain plan):
Query A:
Cardinality: 102
Cost : 204
Total Runtime: 5 secs max
Query B:
Cardinality:27921981
Cost: 14846
Total Runtime:20 mins until user cancelled
All tables are indexed using those columns that used to join against other tables in the FinalView1. According to the explain plan, they have all been used except for the FirstOrder table.
Query A used uniquue index on the FirstOrder Table while Query B performed a full scan.
For query B, I was expecting the Oracle will firstly query the sub-query get the result into the in operator, before executing the main query and therefore should only have minor impact to the performance.
Thanks in advance!
As mentioned from my comment 2 days ago. Someone have actually posted the solution and then have it removed while the answer actually work. After waiting for 2 days the So I designed to post that solution.
That solution suggested that the performance was slow down by the "in" operator. and suggested me to replace it with an inner join
Create Table T1 as
Select
FV.*
from
FinalView1 FV
inner join (
select distinct
CustomerID
from
CriteriaTable
) CT on CT.customerid = FV.customerID;
Result from explain plan was worse then before:
Cardinality:28364465 (from 27921981)
Cost: 15060 (from 14846)
However, it only takes 17 secs. Which is very good!

Get STATUS from table by which join in oracle

I have a query for which based on CRNO I get the STATUS from another table. So the below query is
select a.crno, a.crno_date, a.state, a.status_rank from R4G_OSP.ENODEB a
Where a.crno is not null
and a.crno = 'R4G-MH-NLD-7718'
and a.status_rank is not null
order by 4 asc;
and STATUS table query is
select * from APP_WFM.WFM_CANDIDATE_STATUS where rank = 20
So, now I want to join the query and get the status in the first query. How should I do that
The sample data of both query is below
QUERY 1 SAMPLE DATA
QUERY 2 SAMPLE DATA
Please suggest how should I get the STATUS by joining it
You can use JOIN. Manual Here
select a.crno,
a.crno_date,
a.state,
a.status_rank,
APP_WFM.WFM_CANDIDATE_STATUS.STATUS
from R4G_OSP.ENODEB a
join APP_WFM.WFM_CANDIDATE_STATUS on APP_WFM.WFM_CANDIDATE_STATUS.RANK = a.status_rank
Where a.crno is not null
and a.crno = 'R4G-MH-NLD-7718'
and a.status_rank is not null
order by 4 asc;
If you want only rank 20 add AND a.status_rank = 20 before ORDER BY
Select a.crno,
a.crno_date,
a.state,
a.status_rank
from R4G_OSP.ENODEB a
join APP_WFM.WFM_CANDIDATE_STATUS on APP_WFM.WFM_CANDIDATE_STATUS.RANK = a.status_rank
and a.crno = 'R4G-MH-NLD-7718'
and a.status_rank is not null
order by 4 asc;
Based on the sample data of the table provided it is seen that the primary key relationship is set on WFM.WFM_CANDIDATE_STATUS.RANK and status_rank of another table so you can easily join between those columns

Need to Create calculated columns from input date -18 months in Spotfire for the actual columns

I need to create a report where for each columns there will be a previous column which will give the value from date 18 months back from the date that is given as input. Basically I am getting data from few columns into Spotfire for a particular date and want few of the columns to show the output that was 18 months back.
Code Summary-
This is the code i have to implement into Spotfire. This report takes input of a particular single day's date and gets column values for it. Sub-query gets for few of the values and they are sent to the main query. Typically this report has
few common columns and few other columns which have the value from current date and previous dates for the same columns. I can implement all the columns from the main query, but need suggestions to get values for the previous columns calculated in Spotfire or anyway to implement as an Oracle view since we will be getting only one input for the main query and sub-query will be deducting static no of days/month[in this case its 18 months]
Code Sample:-
select st.x1,
cs.x2 ,
sp.x3, sp.x4,
el.x5 current_zxc, --New data 2
el.xxxx current_zvvxx, --New data 3
por.x6 current_zczxc, --New data 4
el.x7 current_sdcvzv, --New data 5
prev_yr_data.prev_1 previous_czzxczxc,
prev_yr_data.prev_2 previous_xcvv,
prev_yr_data.prev_3 previous_zcvzxz,
prev_yr_data.prev_4 PREVIOUS_czxcvzxv,
prev_yr_data.prev_5 previous_vvvxcvxc,
prev_yr_data.prev_6 previous_zxvxvv,
from table1 cs
inner join table2 usr on cs.xxx = usr.zzzzz
inner join table3 emp on emp.xxx = usr.zzzzz
inner join table4 gbst on cs.xxxs = gbst.zzzzz
inner join table5 sp on cs.xxx = sp.zzzzz
inner join table6 st on sp.xxx = st.zzzzz
inner join table7 ol on ol.xxx = cs.zzzzz
inner join table8 el on el.xxx = ol.zzzzz
inner join table9 spt on trim(upper(el.xxxx)) = trim(upper(spt.xxx))
inner join table10 por on
por.xxx = el.xxxx and
por.xxxx = el.xxxx and
por.xxxx = cs.zzzzz
inner join
(select st.x1,
cs.zzzzz case_zzzzz,
cs.x2 prev_4,
sp.zzzzz ,
sp.x3, sp.x4,
spt.zzzzz ,
spt.xxx prev_1, --Old data 1
el.x5 prev_2, --Old data 2
el.x6 prev_3, --Old data 3
por.xxxx prev_5, --Old data 4
el.x7 prev_6 --Old data 5
from table1 cs
inner join table5 sp on cs.xxxx = sp.zzzzz
inner join table6 st on sp.xxxx = st.zzzzz
inner join table7 ol on ol.xxxx = cs.zzzzz
inner join table8 el on el.xxxxx = ol.zzzzz
inner join table9 spt on trim(upper(el.x_part_name)) = trim(upper(spt.x_part_number))
inner join table10 por on
por.xxx = el.xxxx and
por.xxxx = el.xxxx and
por.xxxx = cs.zzzzz
where ol.date_time between add_months(to_date('date_input','mm/dd/yyyy'), -18) and to_date('date_input','mm/dd/yyyy')
) prev_yr_data on
sp.zzzzz = prev_yr_data.zzzzz and
spt.zzzzz = prev_yr_data.zzzzzz
where ol.date_time >= to_date('date_input','mm/dd/yyyy') and ol.date_time < ( to_date('date_input','mm/dd/yyyy') + 1 )
I would suggest adding a transformation when you bring in the data set to calculate your date 18 months in the future (or past whichever you prefer). Then you can do a self join within Spotfire where [Date] = [18MonthsForward] and bring in the same value column(s) that you desire.
The steps to achieve this look like this when viewed under source information:
2. Select Insert > Transformations...
Add the transformations:
a. Calculate new column
Name: 18MonthsForward
Expression: DateAdd("month",18,[Date])
3. Select Insert > Columns...
Select 'From Current Analysis'
Source location: Data Table
Automatic update.
Match columns:
Date => 18MonthsForward
Ignore columns:
Date
Select join method: LeftOuterJoin
Treat empty values as equal: False
As a step by step instruction you would:
(1) Select Insert >> Transformation
(2) Select Calculation new column from the drop down
(3) Type the expression: DateAdd("month",18,[Date]) and name this whatever you prefer
(4) Select Insert >> Columns
(5) Select from current data and select your current data table
(6) Join on Date and your newly calculated 18MonthsForward date column
(7) Select your value column as the new column
Attached in an image of the data resultant data table. 18 months prior value

Oracle SQL Query to get missing date from two joined tables

I'm trying to write a Oracle SQL query and I'm unable to get the right result.
For the tables below, I would like to first get all records from DEVICE where DEVICE.MODEL='UNITA' and for those results, give me the DEVICE.CUSTOMER_ID's who don't have a record where PROFILE.TYPE='TEST' joining both tables on CUSTOMER_ID. Any ideas on how to formulate this query?
TABLE DEVICE:
ID - sequence generated primary key (NUMBER (10))
DEVICE_NUMBER - unique (varchar)
CUSTOMER_ID (varchar)
MODEL (varchar)
TABLE PROFILE:
ID - sequence generated primary key (NUMBER (10))
CUSTOMER_ID (varchar)
TYPE (varchar)
If I understand the requirement, this should do the trick:
SELECT d.ID, d.Device_Number, d.Customer_ID, d.Model
FROM Device d
LEFT JOIN Profile p ON d.Customer_ID = p.Customer_ID
WHERE d.Model = 'UNITA'
AND (p.ID IS NULL OR p.Type = 'TEST')
It works because of the LEFT JOIN, which will make Profile.ID NULL if there's not a matching Profile row for the Customer_ID. If there is a matching row, the test for Profile.Type = 'TEST' will determine what's included.
There's a SQL Fiddle here. The Fiddle includes the Profile.ID and Profile.Type values in the results because I think they help explain things more clearly.
Addendum: Some confusion on my part over the requirements; this query may be closer to what's needed:
SELECT d.ID, d.Device_Number, d.Customer_ID, d.Model, p.id AS pid, p.type
FROM Device d
LEFT JOIN Profile p ON d.Customer_ID = p.Customer_ID AND p.Type = 'TEST'
WHERE d.Model = 'UNITA'
AND p.ID IS NULL

Resources