Select statement with inner join is taking forever - abap

(....)
DATA: BEGIN OF g00 OCCURS 100,
werks LIKE lqua-werks,
lgort LIKE lqua-lgort,
matnr LIKE lqua-matnr,
charg LIKE lqua-charg,
maktx LIKE makt-maktx,
verme LIKE lqua-verme,
meins LIKE lqua-meins,
dispo LIKE marc-dispo,
END OF g00.
(.....)
CLEAR : g00.
REFRESH : g00.
SELECT lqua~bestq lqua~charg lqua~lgort lqua~lgnum lqua~lgpla
lqua~lgtyp lqua~matnr lqua~meins lqua~verme lqua~werks makt~maktx
makt~matnr makt~spras mara~bismt mara~matnr marc~dispo
marc~matnr marc~werks
INTO (lqua-bestq , lqua-charg , lqua-lgort , lqua-lgnum , lqua-lgpla ,
lqua-lgtyp , lqua-matnr , lqua-meins , lqua-verme , lqua-werks ,
makt-maktx , makt-matnr , makt-spras , mara-bismt , mara-matnr ,
marc-dispo , marc-matnr , marc-werks )
FROM ( lqua
INNER JOIN makt
ON makt~matnr = lqua~matnr
INNER JOIN mara
ON mara~matnr = makt~matnr
INNER JOIN marc
ON marc~werks = lqua~werks
AND marc~matnr = lqua~matnr )
WHERE lqua~bestq IN sbestq
AND lqua~lgnum IN slgnum
AND lqua~lgpla IN slgpla
AND lqua~lgtyp IN slgtyp
AND lqua~matnr IN smatnr
AND lqua~werks IN swerks
AND makt~maktx IN smaktx
AND makt~spras IN sspras
* AND MARA~BISMT IN Sbismt
AND marc~dispo IN sdispo.
MOVE-CORRESPONDING mara TO g00.
MOVE-CORRESPONDING makt TO g00.
MOVE-CORRESPONDING marc TO g00.
MOVE-CORRESPONDING lqua TO g00.
COLLECT g00.
ENDSELECT.
Can anyone help to improve the performance of code above.

Your starting table for the join (LQUA) is not selecting on key or indexed fields, which will always run slower than if you are able to use them.
While there doesn't appear to be a way to join everything on key fields, you might have better luck if you tweak the query to initially pull from MARA (where MATNR is a key field):
FROM ( mara
INNER JOIN makt
ON makt~matnr = mara~matnr
INNER JOIN lqua
ON lqua~matnr = mara~matnr
INNER JOIN marc
ON marc~werks = mara~werks
AND marc~matnr = mara~matnr )...

DO NOT use SELECT END SELECT in the scenario you have described below. Try doing the following :
-> Create a local type with the fields you are picking up select ( lt_yourtype)
( lqua~bestq lqua~charg lqua~lgort lqua~lgnum lqua~lgpla
lqua~lgtyp lqua~matnr lqua~meins lqua~verme lqua~werks makt~maktx
makt~matnr makt~spras mara~bismt mara~matnr marc~dispo
marc~matnr marc~werks )
-> Create work area ( prefer field symbol ) and internal table of the above local type ( lt_yourtype )
-> Replace the given select with :
select lqua~bestq lqua~charg lqua~lgort lqua~lgnum lqua~lgpla
lqua~lgtyp lqua~matnr lqua~meins lqua~verme lqua~werks makt~maktx
makt~matnr makt~spras mara~bismt mara~matnr marc~dispo
marc~matnr marc~werks
into table lt_yourtype
FROM ( lqua
INNER JOIN makt
ON makt~matnr = lqua~matnr
INNER JOIN mara
ON mara~matnr = makt~matnr
INNER JOIN marc
ON marc~werks = lqua~werks
AND marc~matnr = lqua~matnr )
WHERE lqua~bestq IN sbestq
AND lqua~lgnum IN slgnum
AND lqua~lgpla IN slgpla
AND lqua~lgtyp IN slgtyp
AND lqua~matnr IN smatnr
AND lqua~werks IN swerks
AND makt~maktx IN smaktx
AND makt~spras IN sspras
* AND MARA~BISMT IN Sbismt
AND marc~dispo IN sdispo.
loop into lt_yourtype assigning .
*move data to the correct structure and fields here
endloop.

Related

How to insert numerous rows on a table from another table with conditions on Oracle SQL

I do have a problem on how to insert numerous rows of data into a table from an existing table with conditions. So this first code is how I created my table.
CREATE TABLE MARKETING_COMMODITY
AS(
SELECT A.DTIME_SIGNATURE
, A.AMT_SIGNED
, A.CNT_SIGNED
, A.APPLICATION_AMOUNT
, A.PRODUCT
, A.PRODUCT_TYPE
, A.PRODUCT_PRICE
, VSR.NAME_PRODUCER
, vsr.text_model_number
, vsp.partner_name
, vsp.partner_brand
, vspl.salesroom
, vspl.mall
FROM DM_SALES.V_SALES_DM_DATA A
LEFT JOIN DM_SALES.V_SALES_DM_PARTNER VSP ON A.CODE_SALESROOM_PARTNER = VSP.CODE_SALESROOM_PARTNER
LEFT JOIN dm_sales.v_sales_dm_pos_list vspl on a.code_salesroom = vspl.code_salesroom
LEFT JOIN DM_SALES.V_SALES_DM_CONTRACT_BUNDLE VSR ON A.CONTRACT_NUMBER = VSR.CONTRACT_NUMBER
WHERE 1=1
AND a.contract_state <> 'Cancelled'
AND a.cnt_signed=1
AND A.LOAN_TYPE = 'Consumer Loan'
AND (TRUNC(A.DTIME_SIGNATURE) BETWEEN DATE'2022-01-01' AND DATE'2022-08-31')
;
And this is how I'd like to insert my new rows (its like updating the table to get the new data up to the current day)
INSERT INTO MARKETING_COMMODITY
VALUES(
SELECT A.DTIME_SIGNATURE
, A.AMT_SIGNED
, A.CNT_SIGNED
, A.APPLICATION_AMOUNT
, A.PRODUCT
, A.PRODUCT_TYPE
, A.PRODUCT_PRICE
, VSR.NAME_PRODUCER
, vsr.text_model_number
, vsp.partner_name
, vsp.partner_brand
, vspl.salesroom
, vspl.mall
FROM DM_SALES.V_SALES_DM_DATA A
LEFT JOIN DM_SALES.V_SALES_DM_PARTNER VSP ON A.CODE_SALESROOM_PARTNER = VSP.CODE_SALESROOM_PARTNER
LEFT JOIN dm_sales.v_sales_dm_pos_list vspl on a.code_salesroom = vspl.code_salesroom
LEFT JOIN DM_SALES.V_SALES_DM_CONTRACT_BUNDLE VSR ON A.CONTRACT_NUMBER = VSR.CONTRACT_NUMBER
WHERE 1=1
AND a.contract_state <> 'Cancelled'
AND a.cnt_signed=1
AND A.LOAN_TYPE = 'Consumer Loan'
AND (TRUNC(A.DTIME_SIGNATURE) BETWEEN DATE'2022-09-01' AND DATE'2022-09-10')
;
What can you suggest? Thanks!
Don't confuse the syntax for "CREATE TABLE AS SELECT" with the syntax for "INSERT INTO SELECT". Explicitely add the columns you're inserting into and remove the "AS" keyword. This should work:
INSERT INTO MARKETING_COMMODITY
(
dtime_signature
,amt_signed
,cnt_signed
,application_amount
,product
,product_type
,product_price
,name_producer
,text_model_number
,partner_name
,partner_brand
,salesroom
,mall
)
SELECT A.DTIME_SIGNATURE
, A.AMT_SIGNED
, A.CNT_SIGNED
, A.APPLICATION_AMOUNT
, A.PRODUCT
, A.PRODUCT_TYPE
, A.PRODUCT_PRICE
, VSR.NAME_PRODUCER
, vsr.text_model_number
, vsp.partner_name
, vsp.partner_brand
, vspl.salesroom
, vspl.mall
FROM DM_SALES.V_SALES_DM_DATA A
LEFT JOIN DM_SALES.V_SALES_DM_PARTNER VSP ON A.CODE_SALESROOM_PARTNER = VSP.CODE_SALESROOM_PARTNER
LEFT JOIN dm_sales.v_sales_dm_pos_list vspl on a.code_salesroom = vspl.code_salesroom
LEFT JOIN DM_SALES.V_SALES_DM_CONTRACT_BUNDLE VSR ON A.CONTRACT_NUMBER = VSR.CONTRACT_NUMBER
WHERE 1=1
AND a.contract_state <> 'Cancelled'
AND a.cnt_signed=1
AND A.LOAN_TYPE = 'Consumer Loan'
AND (TRUNC(A.DTIME_SIGNATURE) BETWEEN DATE'2022-09-01' AND DATE'2022-09-10')
;

Joining three tables in Snowflake

I am trying to join three tables in Snowflake, but getting an error on a third one, and not sure if I used a good key :
select
a.CALENDAR_DATE
, a.SALES_DOCUMENT
, a.DOCUMENT_NUMBER_CROSS_BORDER
, *bAUBEL
, *b.NETWR_ship*
, a.Delivery_time
, a.Route_label
, ue.order_ID
from DWHM_MALLGROUP.DM_LOG.SHIPMENTS a
left join (
select
AUBEL,
sum(NETWR) as NETWR_ship
from DWHM_MALLGROUP.SRC_SAP_ERP."2LIS_13_VDITM"
where MATNR in ('10027', '10200', '10402', '10500', '10602', '10603', '10650', '10700')
group by AUBEL
) b
on a.DOCUMENT_NUMBER_CROSS_BORDER = b.AUBEL
where
a.CALENDAR_DATE >= '2020-04-01'
and a.ROUTE in ('CZSK12', 'CZSK21', 'CZSK22', 'CZSK23', 'CZSK24', 'CZSK25', 'CZSK26', 'CZSK27', 'CZSK28', 'CZSK29', 'CZSK30', 'CZSK32', 'CZSK33', 'CZSK34', 'CZSK51', 'CZSK53', 'CZSK54', 'CZSK56')
group by a.CALENDAR_DATE, a.SALES_DOCUMENT, a.DOCUMENT_NUMBER_CROSS_BORDER, b.AUBEL, b.NETWR_ship, a.delivery_time, a.Route_LABEL
left join "DWHM_MALLGROUP"."DM_COMMERCIAL"."UNIT_ECONOMICS" as ue
ON a.SALES_DOCUMENT = ue.order_id
where ue.country = 'SI' and ue.delivery_date >= '2019-08-01'
Your 2nd LEFT JOIN should be moved up to before the WHERE clause:
select
a.CALENDAR_DATE
, a.SALES_DOCUMENT
, a.DOCUMENT_NUMBER_CROSS_BORDER
, b.AUBEL
, b.NETWR_ship
, a.Delivery_time
, a.Route_label
, ue.order_ID
from DWHM_MALLGROUP.DM_LOG.SHIPMENTS a
left join (
select
AUBEL,
sum(NETWR) as NETWR_ship
from DWHM_MALLGROUP.SRC_SAP_ERP."2LIS_13_VDITM"
where MATNR in ('10027', '10200', '10402', '10500', '10602', '10603', '10650', '10700')
group by AUBEL
) b
on a.DOCUMENT_NUMBER_CROSS_BORDER = b.AUBEL
left join "DWHM_MALLGROUP"."DM_COMMERCIAL"."UNIT_ECONOMICS" as ue
ON a.SALES_DOCUMENT = ue.order_id
where
a.CALENDAR_DATE >= '2020-04-01'
and a.ROUTE in ('CZSK12', 'CZSK21', 'CZSK22', 'CZSK23', 'CZSK24', 'CZSK25', 'CZSK26', 'CZSK27', 'CZSK28', 'CZSK29', 'CZSK30', 'CZSK32', 'CZSK33', 'CZSK34', 'CZSK51', 'CZSK53', 'CZSK54', 'CZSK56')
and ue.country = 'SI' and ue.delivery_date >= '2019-08-01'
group by a.CALENDAR_DATE, a.SALES_DOCUMENT, a.DOCUMENT_NUMBER_CROSS_BORDER, b.AUBEL, b.NETWR_ship, a.delivery_time, a.Route_LABEL
NOTE: I am not familiar with the *b that you have in the SELECT clause... it looks like another typo to me, so I removed it.
If you are trying to perform the aggregate (GROUP BY) before the 2nd LEFT JOIN, then you can use a CTE:
WITH CTE_1 AS (
select
a.CALENDAR_DATE
, a.SALES_DOCUMENT
, a.DOCUMENT_NUMBER_CROSS_BORDER
, b.AUBEL
, b.NETWR_ship
, a.Delivery_time
, a.Route_label
from DWHM_MALLGROUP.DM_LOG.SHIPMENTS a
left join (
select
AUBEL,
sum(NETWR) as NETWR_ship
from DWHM_MALLGROUP.SRC_SAP_ERP."2LIS_13_VDITM"
where MATNR in ('10027', '10200', '10402', '10500', '10602', '10603', '10650', '10700')
group by AUBEL
) b
on a.DOCUMENT_NUMBER_CROSS_BORDER = b.AUBEL
where
a.CALENDAR_DATE >= '2020-04-01'
and a.ROUTE in ('CZSK12', 'CZSK21', 'CZSK22', 'CZSK23', 'CZSK24', 'CZSK25', 'CZSK26', 'CZSK27', 'CZSK28', 'CZSK29', 'CZSK30', 'CZSK32', 'CZSK33', 'CZSK34', 'CZSK51', 'CZSK53', 'CZSK54', 'CZSK56')
group by a.CALENDAR_DATE, a.SALES_DOCUMENT, a.DOCUMENT_NUMBER_CROSS_BORDER, b.AUBEL, b.NETWR_ship, a.delivery_time, a.Route_LABEL
) c1
select
c1.CALENDAR_DATE
, c1.SALES_DOCUMENT
, c1.DOCUMENT_NUMBER_CROSS_BORDER
, c1.AUBEL
, c1.NETWR_ship
, c1.Delivery_time
, c1.Route_label
, ue.order_ID
left join "DWHM_MALLGROUP"."DM_COMMERCIAL"."UNIT_ECONOMICS" as ue
ON c1.SALES_DOCUMENT = ue.order_id
and ue.country = 'SI' and ue.delivery_date >= '2019-08-01'
This can (and should, IMO) be cleaned up some more, but I am trying to address the question you asked about joining 3 tables.
There are multiple issues with the SQL.
, *bAUBEL
, *b.NETWR_ship*
we only use * for selecting all fields from a table. For example select A.* , B.col1 from Table_a A , Table_B
sequence for join is
SELECT
FROM Table
JOIN other Table
JOIN Condition
WHERE
GROUP BY
HAVING
Try this SQL
SELECT
a.calendar_date,
a.sales_document,
a.document_number_cross_border,
b.aubel,
b.netwr_ship,
a.delivery_time,
a.route_label,
ue.order_id
FROM
dwhm_mallgroup.dm_log.SHIPMENTS a
left join (
select
AUBEL,
sum(NETWR) as NETWR_ship
from DWHM_MALLGROUP.SRC_SAP_ERP."2LIS_13_VDITM"
where MATNR in ('10027', '10200', '10402', '10500', '10602', '10603', '10650', '10700')
group by AUBEL
) b
on a.DOCUMENT_NUMBER_CROSS_BORDER = b.AUBEL
left join "DWHM_MALLGROUP"."DM_COMMERCIAL"."UNIT_ECONOMICS" as ue ON a.sales_document = ue.order_id
WHERE
a.calendar_date >= '2020-04-01'
AND a.route IN (
'CZSK12',
'CZSK21',
'CZSK22',
'CZSK23',
'CZSK24',
'CZSK25',
'CZSK26',
'CZSK27',
'CZSK28',
'CZSK29',
'CZSK30',
'CZSK32',
'CZSK33',
'CZSK34',
'CZSK51',
'CZSK53',
'CZSK54',
'CZSK56'
)
AND ue.country = 'SI'
AND ue.delivery_date >= '2019-08-01'
GROUP BY
a.calendar_date,
a.sales_document,
a.document_number_cross_border,
b.aubel,
b.netwr_ship,
a.delivery_time,
a.route_label
ue.order_id

Sum the results in a union all

I have the following query in SQL.
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
, cast(ap.Codigo as varchar ) CodArtProveedor
, dlp.Precio Publico
, 0 Interior
from Articulos a
join ArticuloProveedores ap on ap.ArticuloId = a.Id
join DetallesListaPrecios DLP on DLP.ArticuloId = A.Id
join ListasPrecios lp on lp.Id = dlp.ListaPreciosId
where lp.Id in ('1')
union all
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
, cast(ap.Codigo as varchar ) CodArtProveedor
, 0
, dlp.Precio
FROM Articulos a
join ArticuloProveedores ap on ap.ArticuloId = a.Id
join DetallesListaPrecios DLP on DLP.ArticuloId = A.Id
join ListasPrecios lp on lp.Id = dlp.ListaPreciosId
where lp.Id in ('4')
And the results I get are something like below:
CodArticulo CodArtProveedor Publico Interior
44380 K-7 697 0
44380 K-7 0 767
00003 IM2757 0 2030
00003 IM2757 1845 0
00006 MTRJ6 156 0
00006 MTRJ6 0 172
00010 BERJ6 156 0
00010 BERJ6 0 172
I need to SUM () the columns PUBLICO and INTERIOR. And I my desired output is something like below.
CodArticulo CodArtProveedor Publico Interior
44380 K-7 697 767
00003 IM2757 1845 2030
00006 MTRJ6 156 172
00010 BERJ6 156 172
What are the suggested methods to get my output as expected?
I would suggest the CTE
;WITH cte(CodArticulo,CodArtProveedor,Publico,Interior) AS
(SELECT cast(A.CodigoArticulo as varchar) CodArticulo
, cast(ap.Codigo as varchar ) CodArtProveedor
, dlp.Precio Publico
, 0 Interior
from Articulos a
join ArticuloProveedores ap on ap.ArticuloId = a.Id
join DetallesListaPrecios DLP on DLP.ArticuloId = A.Id
join ListasPrecios lp on lp.Id = dlp.ListaPreciosId
where lp.Id in ('1')
union all
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
, cast(ap.Codigo as varchar ) CodArtProveedor
, 0
, dlp.Precio
FROM Articulos a
join ArticuloProveedores ap on ap.ArticuloId = a.Id
join DetallesListaPrecios DLP on DLP.ArticuloId = A.Id
join ListasPrecios lp on lp.Id = dlp.ListaPreciosId
where lp.Id in ('4'))
select CodArticulo,CodArtProveedor,SUM(Publico),Sum(Interior) from cte group by CodArticulo,CodArtProveedor
I would suggest to input these UNION results to a temp table ##tempResults and then use Group By and Sum
select CodArticulo, CodArtProveedor,SUM(Publico) ,SUM(Interior) from ##tempResults
group by CodArticulo,CodArtProveedor
I'm not completely familiar with your data model, however based on the query, placing a condition inside the SUM may allow you to do the query in a single pass. In the below example a single select (no union) is executed, and a CASE statement is being used inside the SUM to get the desired result:
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
,cast(ap.Codigo as varchar ) CodArtProveedor
,SUM(CASE WHEN '1' THEN dlp.Precio ELSE 0 END) Publico
,SUM(CASE WHEN '4' THEN dlp.Precio ELSE 0 END) Interior
FROM Articulos a
JOIN ArticuloProveedores ap ON ap.ArticuloId = a.Id
JOIN DetallesListaPrecios DLP ON DLP.ArticuloId = A.Id
JOIN ListasPrecios lp ON lp.Id = dlp.ListaPreciosId
WHERE lp.Id in ('1', '4')
GROUP BY A.CodigoArticulo, ap.Codigo
First of 2 possible answers:
Place your UNION query into a Common Table Expression or Sub-Query, then put the group by condition around the outside. Example Below:
SELECT CodArticulo
,CodArtProveedor
,SUM(Publico) as TotalPublico
,SUM(Interior) as TotalInterior
FROM (
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
,cast(ap.Codigo as varchar ) CodArtProveedor
,dlp.Precio Publico
,0 Interior
FROM Articulos a
JOIN ArticuloProveedores ap ON ap.ArticuloId = a.Id
JOIN DetallesListaPrecios DLP ON DLP.ArticuloId = A.Id
JOIN ListasPrecios lp ON lp.Id = dlp.ListaPreciosId
WHERE lp.Id in ('1')
UNION ALL
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
,cast(ap.Codigo as varchar ) CodArtProveedor
,0
,dlp.Precio
FROM Articulos a
JOIN ArticuloProveedores ap ON ap.ArticuloId = a.Id
JOIN DetallesListaPrecios DLP ON DLP.ArticuloId = A.Id
JOIN ListasPrecios lp ON lp.Id = dlp.ListaPreciosId
WHERE lp.Id in ('4')
) d
GROUP BY CodArticulo, CodArtProveedor
This is your query into #Temp
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
, cast(ap.Codigo as varchar ) CodArtProveedor
, dlp.Precio Publico
, 0 Interior
INTO #TEMP
from Articulos a
join ArticuloProveedores ap on ap.ArticuloId = a.Id
join DetallesListaPrecios DLP on DLP.ArticuloId = A.Id
join ListasPrecios lp on lp.Id = dlp.ListaPreciosId
where lp.Id in ('1')
union all
SELECT cast(A.CodigoArticulo as varchar) CodArticulo
, cast(ap.Codigo as varchar ) CodArtProveedor
, 0
, dlp.Precio
FROM Articulos a
join ArticuloProveedores ap on ap.ArticuloId = a.Id
join DetallesListaPrecios DLP on DLP.ArticuloId = A.Id
join ListasPrecios lp on lp.Id = dlp.ListaPreciosId
where lp.Id in ('4')
This is you have to add, that's all.
select sum(Publico),sum(Interior), CodArticulo, CodArtProveedor
from #TEMP
group by CodArticulo, CodArtProveedor

Inner join with sub query in PostgreSQL

In my query I need to join with a sub query on a derived column :
select w1.wk_id,
(floor(td1.military_hour/4)*4) as military_hour_group ,
w1.end_date as end_date
from work_instances w1
inner join time_table td1 on w1.end_time = td1.time_id
inner join
(
select (floor(td2.military_hour/4)*4) as td2_military_hour_group,
(floor(td3.military_hour/4)*4) as td3_military_hour_group, wk_id
from task_instances t1
inner join time_table td2 on t1.end_time = td1.time_id
inner join time_table td3 on t1.start_time = td3.time_id
) tq1
on tq1.td2_military_hour_group = military_hour_group
and tq1.td3_military_hour_group = military_hour_group
and tq1.wk_id = w1.wf_id
It says Invalid operation: column "military_hour_group" does not exist in w1, td1, unnamed_join, tq1;
What am I doing wrong?
Please help.
Try below: military_hour_group is your calculated column and that's why it is showing that error
select w1.wk_id,
(floor(td1.military_hour/4)*4) as military_hour_group ,
w1.end_date as end_date
from work_instances w1
inner join time_table td1 on w1.end_time = td1.time_id
inner join
(
select (floor(td2.military_hour/4)*4) as td2_military_hour_group,
(floor(td3.military_hour/4)*4) as td3_military_hour_group, wk_id
from task_instances t1
inner join time_table td2 on t1.end_time = td1.time_id
inner join time_table td3 on t1.start_time = td3.time_id
) tq1
on tq1.td2_military_hour_group = (floor(td1.military_hour/4)*4)
and tq1.td3_military_hour_group = (floor(td1.military_hour/4)*4)
and tq1.wk_id = w1.wf_id
Okay Use like below mention
select *
from (select w1.wk_id, (floor(td2.military_hour/4)*4) as military_hour_group , w1.end_date as end_date
from work_instances w1 inner join time_table td1 on w1.end_time = td1.time_id) table1 inner join (select (floor(td2.military_hour/4)*4) as td2_military_hour_group, (floor(td3.military_hour/4)*4) as td3_military_hour_group, wk_id
from task_instances t1 inner join time_table td2 on t1.end_time = td1.time_id inner join time_table td3 on t1.start_time = td3.time_id ) tabl2 on tabl2.td2_military_hour_group = table1.military_hour_group and tabl2.td3_military_hour_group = table1.military_hour_group and tabl2.wk_id = table1.wf_id

SQL JOIN between A, B and C mixing full and left join

I'd like to know if there is a better way to create my left join in the below example:
SELECT TOP 10 COALESCE(A.COD_PRODUCT, B.COD_PRODUCT),
COALESCE(A.COD_FAMILY, B.COD_FAMILY),
COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT),
A.MASS
B.VOLUME
C.PRICE
FROM FIRSTTABLE A FULL JOIN SECONDTABLE B ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT JOIN THIRDTABLE C ON C.COD_PRODUCT = COALESCE(A.COD_PRODUCT,B.COD_PRODUCT)
AND C.COD_FAMILY = COALESCE(A.COD_FAMILY, B.COD_FAMILY)
AND C.DATE_EXTRACT = COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT)
That kind of jointure takes long time and I suspect it to be highly expensive and improvable
EDIT: I'd like to improve this SELECT FROM JOIN statement in a View.
You could split the query into two: gather all data matching FIRSTTABLE. And then union it with all data matching SECONDTABLE that is not in FIRSTTABLE.
That should allow SQL Server to use the indexes on these tables better.
SELECT A.COD_PRODUCT,
A.COD_FAMILY,
A.DATE_EXTRACT,
A.MASS,
B.VOLUME,
C.PRICE
FROM FIRSTTABLE A
LEFT OUTER JOIN SECONDTABLE B
ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT OUTER JOIN THIRDTABLE C
ON C.COD_PRODUCT = A.COD_PRODUCT
AND C.COD_FAMILY = A.COD_FAMILY
AND C.DATE_EXTRACT = A.DATE_EXTRACT
UNION ALL
SELECT B.COD_PRODUCT,
B.COD_FAMILY,
B.DATE_EXTRACT,
NULL AS MASS,
B.VOLUME,
C.PRICE
FROM SECONDTABLE B
LEFT OUTER JOIN THIRDTABLE C
ON C.COD_PRODUCT = B.COD_PRODUCT
AND C.COD_FAMILY = B.COD_FAMILY
AND C.DATE_EXTRACT = B.DATE_EXTRACT
WHERE NOT EXISTS (SELECT 1
FROM FIRSTTABLE A
WHERE A.COD_PRODUCT = B.COD_PRODUCT
AND A.COD_FAMILY = B.COD_FAMILY
AND A.DATE_EXTRACT = B.DATE_EXTRACT)
Compare the execution plan with this replacement join:
LEFT JOIN THIRDTABLE C
ON (C.COD_PRODUCT = A.COD_PRODUCT or C.COD_PRODUCT = B.COD_PRODUCT)
AND (C.COD_FAMILY = A.COD_FAMILY or C.COD_FAMILY = B.COD_FAMILY)
AND (C.DATE_EXTRACT =A.DATE_EXTRACT or C.DATE_EXTRACT = B.DATE_EXTRACT)
You might can achieve the same result with a UNION or UNION ALL
WITH cte AS (
SELECT
A.COD_PRODUCT,
A.COD_FAMILY,
A.DATE_EXTRACT,
A.MASS,
NULL as VOLUME
FROM
FIRSTTABLE A
UNION
SELECT
B.COD_PRODUCT,
B.COD_FAMILY,
B.DATE_EXTRACT,
NULL,
B.VOLUME
FROM
FIRSTTABLE A
)
SELECT
*
FROM
cte AB
LEFT JOIN
THIRDTABLE C ON C.COD_PRODUCT = AB.COD_PRODUCT
AND C.COD_FAMILY = AB.COD_FAMILY
AND C.DATE_EXTRACT = AB.DATE_EXTRACT
If you can have Mass and Volume for the product,family,extract combination you can use aggregate to join A and B together
WITH cte AS (
SELECT
COD_PRODUCT,
COD_FAMILY,
DATE_EXTRACT,
MAX(MASS) MASS,
MAX(VOLUME) VOLUME
FROM (
SELECT
A.COD_PRODUCT,
A.COD_FAMILY,
A.DATE_EXTRACT,
A.MASS,
NULL as VOLUME
FROM
FIRSTTABLE A
UNION ALL
SELECT
B.COD_PRODUCT,
B.COD_FAMILY,
B.DATE_EXTRACT,
NULL,
B.VOLUME
FROM
FIRSTTABLE A
) T
GROUP BY
COD_PRODUCT,
COD_FAMILY,
DATE_EXTRACT
)
SELECT
*
FROM
cte AB
LEFT JOIN
THIRDTABLE C ON C.COD_PRODUCT = AB.COD_PRODUCT
AND C.COD_FAMILY = AB.COD_FAMILY
AND C.DATE_EXTRACT = AB.DATE_EXTRACT
You can try this:
--- isolate the full join data from a and b into a temp table
SELECT
COD_PRODUCT= COALESCE(A.COD_PRODUCT, B.COD_PRODUCT),
COD_FAMILY= COALESCE(A.COD_FAMILY, B.COD_FAMILY),
DATE_EXTRACT= COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT),
MASS= A.MASS,
VOLUME= B.VOLUME
INTO #TEMP
FROM FIRSTTABLE A
FULL JOIN SECONDTABLE B
ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
-- add index clustered onto table (covering index)
CREATE CLUSTERED INDEX ix_tempCIndex ON #Temp ([COD_PRODUCT],[COD_FAMILY],[DATE_EXTRACT],[MASS],[VOLUME]);
-- left join C to this temp table
SELECT TOP 10
T.*, C.PRICE
FROM #TEMP T
LEFT JOIN THIRDTABLE C
ON C.COD_PRODUCT = T.COD_PRODUCT
AND C.COD_FAMILY = T.COD_FAMILY
AND C.DATE_EXTRACT = T.DATE_EXTRACT
-- drop temp table
DROP TABLE #TEMP
A coalesce or an OR inside of a join is going to slow down the query a lot. Depending on the size of the table, a better answer might be to join to table c twice. Once on table a and again on table B, then coalesce inside of your select clause.
SELECT TOP 10 COALESCE(A.COD_PRODUCT, B.COD_PRODUCT,c.COD_PRODUCT,ca.COD_PRODUCT),
COALESCE(A.COD_FAMILY, B.COD_FAMILY,c.COD_FAMILY,ca.COD_FAMILY),
COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT,c.DATE_EXTRACT,ca.DATE_EXTRACT),
A.MASS
B.VOLUME
C.PRICE
FROM FIRSTTABLE A
FULL JOIN SECONDTABLE B
ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT JOIN THIRDTABLE C
ON C.COD_PRODUCT = A.COD_PRODUCT
AND C.COD_FAMILY = A.COD_FAMILY
AND C.DATE_EXTRACT = A.DATE_EXTRACT
LEFT JOIN THIRDTABLE Ca
ON Ca.COD_PRODUCT = b.COD_PRODUCT
AND Ca.COD_FAMILY = b.COD_FAMILY
AND Ca.DATE_EXTRACT = b.DATE_EXTRACT