I want to select all notifications with the relevant information and I also want the notifications that have no equipment. But when I use below join, I only get the ones where the equipment is not null. Shouldn't the left outer join make sure I get everything in table VIQMEL?
I do get the notifications that have no equipment if I delete the AND K~SPRAS EQ 'E'.
Any ideas on how to resolve this?
SELECT v~qmnum,
v~qmart,
t~istat,
t~txt30,
v~aufnr,
v~tplnr,
v~equnr,
v~btpln,
v~qmnam,
v~qmgrp,
v~qmcod,
ct~kurztext,
gt~kurztext,
v~beber,
k~eqktx,
v~qmtxt,
ax~pltxt,
fx~pltxt,
v~priok,
v~erdat,
s~tdid,
a~reltype,
z~aduser
FROM viqmel AS v
LEFT OUTER JOIN iflot AS f ON v~tplnr = f~tplnr
LEFT OUTER JOIN jest AS j ON j~objnr = v~objnr
LEFT OUTER JOIN tj02t AS t ON t~istat = j~stat
LEFT OUTER JOIN iflotx AS fx ON fx~tplnr = v~tplnr
LEFT OUTER JOIN iflotx AS ax ON ax~tplnr = v~btpln
LEFT OUTER JOIN qpct AS ct ON ct~code = v~qmcod
LEFT OUTER JOIN eqkt AS k ON v~equnr = k~equnr
LEFT OUTER JOIN qpgt AS gt ON gt~codegruppe = v~qmgrp
LEFT OUTER JOIN stxh AS s ON s~tdname = v~qmnum
LEFT OUTER JOIN srgbtbrel AS a ON v~qmnum = a~instid_a
LEFT OUTER JOIN zzid_map AS Z ON v~qmnam = z~sapuser
WHERE t~spras = #sy-langu
AND v~qmnum LIKE #p_qmnum
AND v~equnr LIKE #p_equnr
AND v~qmnam LIKE #p_qmnam
AND v~aufnr LIKE #p_aufnr
AND f~tplnr LIKE #p_tplnr
AND t~istat LIKE #p_istat
AND v~beber LIKE #p_beber
AND j~inact <> #abap_true
AND t~istat <> 'I0076'
AND t~spras = 'E'
AND fx~spras = 'E'
AND k~spras = 'E'
INTO TABLE #DATA(et_notifs).
Side note:EQKT is equipment short text (not equipment) and EQKT~SPRAS is language.
Problem: You wrote your condition to only select English text, which is why it ignores records that are joined with non English or ones, that aren't joined at all.
So if you have ( number represents a key ) your text table
1 E ....
2 X ....
3 N ....
4 E ....
After a join texts from table join like this
1 E ....
2 [initial]
3 [initial]
4 E ....
After filter you're left with
1 E ....
4 E ....
Solutions
Unnecessarily complicated solution, using exclusion subquery
With restrictions of SAP Open SQL, excluding joins, as well as joins that including records based on absence of corresponding records from other tables is not possible.
The workarounds for excluding joins are generally sub-queries.
You could add a subquery to check select languages based on your filter and ignore that filter in other cases (to include empty records). Try to replace and K~SPRAS EQ 'E' with the following (the idea here is to take the language if it exists and bypass the condition otherwise):
and ( K~SPRAS in (select SPRAS from EQKT where EQUNR=V~EQUNR and spras = 'E')
OR NOT EXISTS (select SPRAS from EQKT where spras = 'E')
)
The idea here is you have 2 subqueries. One of them uses a positive check to include all the languages you need. The other uses a negative check and includes records where that particular language does not exist.
Update: Minimalistic solution (left join on key + condition)
After looking at your question with clear head, I noticed my solution might be too complicated for your needs (even though it will work).
A standard left join on key + condition will fulfill your requirement. Move your and K~SPRAS EQ 'E' into join condition and it will select exactly the way you want it to (A standard left join). Also, if I recall correctly outer keyword doesn't do anything on left/right joins.
LEFT JOIN EQKT AS K ON V~EQUNR EQ K~EQUNR AND K~SPRAS EQ 'E'
PS: Aliases and redundant joins in the question aren't helping with its readability.
Related
Write a query to show ALL building names, their metering company name and meter type for all buildings that do not have postpaid meters.
The image 1 is the result that I should get and image 2 is the results that i am getting:
USE Ultimate_DataBase
GO
SELECT [Bld_Name], [Elec_company_name], [Mtype_Name]
FROM [dbo].[Metering_Company] A
FULL OUTER JOIN [dbo].[Metering_Type] D
ON A.[MType_ID]= D.MType_ID
FULL OUTER JOIN [dbo].[Building_metering] B
ON A.[Elec_ID]= B.[Elec_ID]
FULL OUTER JOIN [dbo].[Building] C
ON C.[Bld_ID]= B.[Bld_ID]
WHERE [Mtype_Name] != 'POSTPAID'
Try moving the WHERE logic to the corresponding ON clause:
SELECT [Bld_Name], [Elec_company_name], [Mtype_Name]
FROM [dbo].[Metering_Company] A
FULL OUTER JOIN [dbo].[Metering_Type] D
ON A.[MType_ID]= D.MType_ID AND
[Mtype_Name] != 'POSTPAID' -- change is here
FULL OUTER JOIN [dbo].[Building_metering] B
ON A.[Elec_ID]= B.[Elec_ID]
FULL OUTER JOIN [dbo].[Building] C
ON C.[Bld_ID]= B.[Bld_ID];
Note: Please add aliases to your select clause. They are not mandatory, assuming no two tables ever have columns by the same name, but just having aliases would have made your question easier to answer.
FULL JOIN isn't seem necessary -- in fact FULL JOIN is almost never needed, and especially not for routine JOINs in a well-structured database.
The structure of the question suggests NOT EXISTS:
SELECT b.*
FROM dbo.Building b
WHERE NOT EXISTS (SELECT 1
FROM dbo.Building_metering bm JOIN
dbo.Metering_Company mc
ON bm.Elec_ID = mc.Elec_ID JOIN
dbo.Metering_Type mt
ON mt.MType_ID = mc.MType_ID
WHERE bm.Bld_ID = b.Bld_ID AND mt.Mtype_Name = 'POSTPAID'
);
You can also express this as a LEFT JOIN and filtering:
SELECT b.*
FROM dbo.Building b LEFT JOIN
dbo.Building_metering bm
ON bm.Bld_ID = b.Bld_ID LEFT JOIN
dbo.Metering_Company mc
ON bm.Elec_ID = mc.Elec_ID LEFT JOIN
dbo.Metering_Type mt
ON mt.MType_ID = mc.MType_ID AND
mt.Mtype_Name = 'POSTPAID'
WHERE mt.MType_ID IS NULL;
This allows you to select columns from any of the tables.
Notes:
FULL JOIN is almost never needed.
Use meaningful table aliases! Arbitrary letters mean nothing. Use table abbreviations.
Escaping column and table names with square braces just makes code harder to write and to read.
USE Ultimate_DataBase
GO
SELECT [Bld_Name], [Elec_company_name], [Mtype_Name]
FROM [dbo].[Metering_Company] A
LEFT JOIN [dbo].[Metering_Type] D
ON A.[MType_ID]= D.MType_ID
LEFT JOIN [dbo].[Building_metering] B
ON A.[Elec_ID]= B.[Elec_ID]
LEFT JOIN [dbo].[Building] C
ON C.[Bld_ID]= B.[Bld_ID]
Use this
My current query show the data from the table called "Buque" and has some references from another tables. The problem is when i execute the query it never shows the result because it consumes too much memory i guess.
The current query i have
select buq.buq_codigo, tbu.tbu_codigo, tbu.tbu_nombre, pai.pai_codigo, pai.pai_nombre,
pue.pto_codigo, pue.pto_nombre, lin.lin_codigo, lin.lin_nombre, tra.tra_codigo,
tra.tra_nombre, buq.buq_nombre, buq.buq_des, buq.num_trb, buq.num_eslora,
buq.max_tons, buq.reg_lloyd, buq.buq_codigo1, buq.codigo_omi,
case buq.buq_estado when 'A' then 'Activo' else 'Inactivo' end as buq_estado
from publico.mae_buque as buq, publico.mae_tipbuque as tbu, publico.mae_pais as pai,
publico.mae_puerto as pue, publico.mae_linea as lin, publico.mae_trafico as tra
where buq.tbu_codigo = tbu.tbu_codigo or
buq.pai_codigo = pai.pai_codigo or
buq.pto_codigo = pue.pto_codigo or
buq.lin_codigo = lin.lin_codigo or
buq.tra_codigo = tra.tra_codigo
I also tried with inner joins but the problem is it returns me the data that meets the conditions of the joins. In other words, if the join has data to compare, returns the name, if not, show the null data.
The query must return me 611 records, with inner joins returns 68 records.
Concerning your desired result, use left outer joins, which fill up any non-existing rows of the right hand side table with null-values;
Concerning the out of memory issue, note that you used or to connect your tables; this actually leads to the fact that almost every record of the involved tables is connected to almost every other record (almost a cross join / cartesian product); This can get very large if you connect 6 tables...
select buq.buq_codigo, tbu.tbu_codigo, tbu.tbu_nombre, pai.pai_codigo, pai.pai_nombre,
pue.pto_codigo, pue.pto_nombre, lin.lin_codigo, lin.lin_nombre, tra.tra_codigo,
tra.tra_nombre, buq.buq_nombre, buq.buq_des, buq.num_trb, buq.num_eslora,
buq.max_tons, buq.reg_lloyd, buq.buq_codigo1, buq.codigo_omi,
case buq.buq_estado when 'A' then 'Activo' else 'Inactivo' end as buq_estado
from publico.mae_buque as buq
left outer join publico.mae_tipbuque as tbu on buq.tbu_codigo = tbu.tbu_codigo
left outer join publico.mae_pais as pai on (buq.pai_codigo = pai.pai_codigo)
left outer join publico.mae_puerto as pue on (buq.pto_codigo = pue.pto_codigo)
left outer join publico.mae_linea as lin on (buq.lin_codigo = lin.lin_codigo)
left outer join publico.mae_trafico as tra on (buq.tra_codigo = tra.tra_codigo)
You have to use left outer join:
select *
from
publico.mae_buque as buq
left outer join publico.mae_tipbuque as tbu on (buq.tbu_codigo = tbu.tbu_codigo)
left outer join publico.mae_pais as pai on (buq.pai_codigo = pai.pai_codigo)
left outer join publico.mae_puerto as pue on (buq.pto_codigo = pue.pto_codigo )
left outer join publico.mae_linea as lin on (buq.lin_codigo = lin.lin_codigo)
left outer join publico.mae_trafico as tra on (buq.tra_codigo = tra.tra_codigo);
Query 1
select count(1)
from sdb_snmp_sysdata s
left join sdb_snmp_entphysicaltable e on s.source = e.source **and e.class = 3**
left join SDB_DF_DEVICE_DNS dns on dns.source = s.source
left join sdb_fdb_node f on upper(f.oldnodeid) = upper(dns.dns_name)
where (regexp_like(s.descr, 'NFXS-F FANT-F ALCATEL-LUCENT|Motorola APEX3000')
or regexp_like(e.descr, 'Motorola BSR64000 HD 100A Redundant Chassis|AS2511-RJ chassis')
or trim(e.ModelName) in ('RFGW1', 'ARCT01949', 'ARCT03253', 'UBR10012', 'WS-C3750-48TS-S', 'WS-C3750V2-48TS-S')
or e.name like '%Nexus5596 Chassis%')
Query 2:
select count(1)
from sdb_snmp_sysdata s
left join sdb_snmp_entphysicaltable e on s.source = e.source
left join SDB_DF_DEVICE_DNS dns on dns.source = s.source
left join sdb_fdb_node f on upper(f.oldnodeid) = upper(dns.dns_name)
where (regexp_like(s.descr, 'NFXS-F FANT-F ALCATEL-LUCENT|Motorola APEX3000')
or regexp_like(e.descr, 'Motorola BSR64000 HD 100A Redundant Chassis|AS2511-RJ chassis')
or trim(e.ModelName) in ('RFGW1', 'ARCT01949', 'ARCT03253', 'UBR10012', 'WS-C3750-48TS-S', 'WS-C3750V2-48TS-S')
or e.name like '%Nexus5596 Chassis%') **and e.class = 3**
The above two queries return different number of rows by changing e.class condition from on clause to where clause. I am unable to figure out. any help is appreciated.
My Understanding:
query 1 left outer join between sysdata and entphysicaltable hash join happens after full scan of individual tables.
in the second query 2 join happens after entphysicaltable is reduced to records containing only entphysicaltable.class = 3.
to me the query makes same sense but returns different results.
I can relate to this question I would like to know a concrete reason.
The best explanation is on a little example. Let have two tables
TABLE A
C1
----------
1
2
TABLE B
C1 C2
---------- -
1 x
Then the query with the filter B.c2 = 'x' in the ON clause returns 2 rows
select *
from A left outer join B
on A.c1 = B.c1 and B.c2 = 'x';
C1 C1 C2
---------- ---------- --
1 1 x
2
while when the filter is moved in the WHERE clause, only one row is delivered
select *
from A left outer join B
on A.c1 = B.c1
WHERE B.c2 = 'x';
C1 C1 C2
---------- ---------- --
1 1 x
The WHERE clause simple overrules the OUTER JOIN row missing logik - wee all know that NULL is not equal 'x', so the second row is discarded.
BWT if you see in the old join syntax constructs like B.c2(+) = 'x' this is the very same thema.
If I read your question right, then it simply comes down to how a LEFT JOIN works.
The way a (outer) LEFT JOIN works is that it will join what's on your left side with what's on your right side.
And then it being an outer join it will try to add NULL values to the right, for the situation where there is no match on the right.
However, by you adding your constraints in the WHERE clause, you're telling the query engine to filter out the rows where there is NULL because they will not match your WHERE clause.
If you have the filters in your ON clause - the query engine will not remove/filter out the NULL rows.
This happens because the WHERE is 'executed' after the JOINs.
That's why you get different number of rows, because an OUTER join functions differently based on whether you use the ON or the WHERE clause.
So if you want the join to include NULL rows, you'll need to use the ON clause.
I have encountered very strange behavior of my query and I wasted a lot of time to understand what causes it, in vane. So I am asking for your help.
SELECT count(*) FROM main_table
LEFT JOIN front_table ON front_table.pk = main_table.fk_front_table
LEFT JOIN info_table ON info_table.pk = front_table.fk_info_table
LEFT JOIN key_table ON key_table.pk = COALESCE(info_table.fk_key_table, front_table.fk_key_table_1, front_table.fk_key_table_2)
LEFT JOIN side_table ON side_table.fk_front_table = front_table.pk
WHERE side_table.pk = (SELECT MAX(pk) FROM side_table WHERE fk_front_table = front_table.pk)
OR side_table.pk IS NULL
Seems like a simple join query, with coalesce, I've used this technique before(not too many times) and it worked right.
In this query I don't ever get nulls for side_table.pk. If I remove coalesce or just don't use key_table, then the query returns rows with many null side_table.pk, but if I add coalesce join, I can't get those nulls.
It seems key_table and side_table don't have anything in common, but the result is so weird.
Also, when I don't use side_table and WHERE clause, the count(*) result with coalesce and without differs, but I can't see any pattern in rows missing, it seems random!
Real query:
SELECT ECHANGE.EXC_AUTO_KEY, STOCK_RESERVATIONS.STR_AUTO_KEY FROM EXCHANGE
LEFT JOIN WO_BOM ON WO_BOM.WOB_AUTO_KEY = EXCHANGE.WOB_AUTO_KEY
LEFT JOIN VIEW_WO_SUB ON VIEW_WO_SUB.WOO_AUTO_KEY = WO_BOM.WOO_AUTO_KEY
LEFT JOIN STOCK stock3 ON stock3.STM_AUTO_KEY = EXCHANGE.STM_AUTO_KEY
LEFT JOIN STOCK stock2 ON stock2.STM_AUTO_KEY = EXCHANGE.ORIG_STM
LEFT JOIN CONSIGNMENT_CODES con2 ON con2.CNC_AUTO_KEY = stock2.CNC_AUTO_KEY
LEFT JOIN CONSIGNMENT_CODES con3 ON con3.CNC_AUTO_KEY = stock3.CNC_AUTO_KEY
LEFT JOIN CI_UTL ON CI_UTL.CUT_AUTO_KEY = EXCHANGE.CUT_AUTO_KEY
LEFT JOIN PART_CONDITION_CODES pcc2 ON pcc2.PCC_AUTO_KEY = stock2.PCC_AUTO_KEY
LEFT JOIN PART_CONDITION_CODES pcc3 ON pcc3.PCC_AUTO_KEY = stock3.PCC_AUTO_KEY
LEFT JOIN STOCK_RESERVATIONS ON STOCK_RESERVATIONS.STM_AUTO_KEY = stock3.STM_AUTO_KEY
LEFT JOIN WAREHOUSE wh2 ON wh2.WHS_AUTO_KEY = stock2.WHS_ORIGINAL
LEFT JOIN SM_HISTORY ON (SM_HISTORY.STM_AUTO_KEY = EXCHANGE.ORIG_STM AND SM_HISTORY.WOB_REF = EXCHANGE.WOB_AUTO_KEY)
LEFT JOIN RC_DETAIL ON stock3.RCD_AUTO_KEY = RC_DETAIL.RCD_AUTO_KEY
LEFT JOIN RC_HEADER ON RC_HEADER.RCH_AUTO_KEY = RC_DETAIL.RCH_AUTO_KEY
LEFT JOIN WAREHOUSE wh3 ON wh3.WHS_AUTO_KEY = COALESCE(RC_DETAIL.WHS_AUTO_KEY, stock3.WHS_ORIGINAL, stock3.WHS_AUTO_KEY)
WHERE STOCK_RESERVATIONS.STR_AUTO_KEY = (SELECT MAX(STR_AUTO_KEY) FROM STOCK_RESERVATIONS WHERE STM_AUTO_KEY = stock3.STM_AUTO_KEY)
OR STOCK_RESERVATIONS.STR_AUTO_KEY IS NULL
Removing LEFT JOIN WAREHOUSE wh3 gives me about unique EXC_AUTO_KEY values with a lot of NULL STR_AUTO_KEY, while leaving this row removes all NULL STR_AUTO_KEY.
I recreated simple tables with numbers with the same structure and query works without any problems o.0
I have a feeling COALESCE is acting as a REQUIRED flag for the joined table, hence shooting the LEFT JOIN to become an INNER JOIN.
Try this:
SELECT COUNT(*)
FROM main_table
LEFT JOIN front_table ON front_table.pk = main_table.fk_front_table
LEFT JOIN info_table ON info_table.pk = front_table.fk_info_table
LEFT JOIN key_table ON key_table.pk = NVL(info_table.fk_key_table, NVL(front_table.fk_key_table_1, front_table.fk_key_table_2))
LEFT JOIN (SELECT fk_, MAX(pk) as pk FROM side_table GROUP BY fk_) st ON st.fk_ = front_table.pk
NVL might behave just the same though...
I undertood what was the problem (not entirely though): there is a LEFT JOIN VIEW_WO_SUB in original query, 3rd line. It causes this query to act in a weird way.
When I replaced the view with the other table which contained the information I needed, the query started returning right results.
Basically, with this view join, NVL, COALESCE or CASE join with combination of certain arguments did not work along with OR clause in WHERE subquery, all rest was fine. ALthough, I could get the query to work with this view join, by changing the order of joined tables, I had to place table participating in where subquery to the bottom.
I have a query as below
select --------
from table a
left outer join ....c
where
(a.column='123') and (c.column='456')
I would like to
include "(c.column='456')" only when (a.column='123') is not null
how do I do that in a single query ? or do I need to write two separate queries ?
Should be pretty straightforward :
select --------
from table
left outer join....
where (Condition A IS NULL) OR (condition A AND condition B)
UPDATED: For your conditions:
where (a.column is null) or (a.column='123' and c.column='456')
It will include a a row if it's a.column is null or if bot a.column and c.column have valid values.
As I understand your requirement this is the sql you want
select distinct cm.credit_amt,e.credit_lifetime,e.credit_desc,e.icom_code,e.entry_hint,
e.credit_id,e.credit_type_id,e.recontract_period,a.class_desc,a.offer_id,
a.offer_class_id
from rti_retention.package a
left outer join rti_retention.offer_class_credit b on (a.offer_id=b.offer_id
and a.offer_class_id=b.offer_class_id
and a.customer_type_id=b.customer_type_id)
left outer join rti_retention.credit_pre_bundle c on (b.credit_id=c.credit_id)
left outer join rti_retention.credit e on (c.credit_id=e.credit_id)
left outer join rti_retention.credit_mix_amount cm on (cm.credit_id=c.credit_id and cm.prod_mix_id=a.prod_mix_id)
where a.offer_class_id not in (1,2,16)
and a.channel_id=5 and a.customer_type_id=1
and a.offer_id='6055'
and c.prod_mix_id = case when (select count(*)
from rti_retention.credit_pre_bundle c1
where c1.prod_mix_id='1000' ) > 1 then '1000' else c.prod_mix_id end
and e.icom_code is not null
some time there will be some sql syntax errors. due to i havent full data base i wrote sql on mind. cant test it.