How to include column values as null even when condition is not met? - sql

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

Related

How can I left outer join SQL Server using on?

I would like to join two tables into master table (on to many) but I keep getting an error
Incorrect syntax near C.showdepartmentinventory_id
My code:
CREATE VIEW view_transactionshowidea
AS
SELECT
A.showidea_id, A.showideaupdatetype_id, A.showidea_proposedtitle,
A.showidea_fixtitle,
B.showinventorycategory_id, B.showinventorycategory_name,
C.showinventorydepartment_id, C.showinventorydepartment_name,
A.shoidea_duration, A.showidea_segment, A.showidea_PIC,
A.showidea_concept, A.showidea_isdisabled
FROM
transaction_showidea AS A
LEFT OUTER JOIN
view_showideainventory AS B
LEFT OUTER JOIN
view_showideainventorydepartment AS C ON showinventorycategory_id = B.showinventorycategory_id
AND showinventorycategory_name = C.showinventorydepartment_id
What is the problem with my query?
Each JOIN should be followed by its ON clause. The sources of your JOIN keys are not clear, but something like this:
FROM transaction_showidea si LEFT OUTER JOIN
view_showideainventory sii
ON si.showinventorycategory_id = sii.showinventorycategory_id LEFT OUTER JOIN
view_showideainventorydepartment siid
ON sii.showinventorycategory_name = siid.showinventorydepartment_id
Note that this introduces meaninful table aliases -- abbreviations for the table names. And all column references are qualified.
You need to specify "ON" right after your join statement like this:
CREATE VIEW view_transactionshowidea AS
SELECT A.showidea_id, A.showideaupdatetype_id, A.showidea_proposedtitle,
A.showidea_fixtitle, B.showinventorycategory_id, B.showinventorycategory_name,
C.showinventorydepartment_id, C.showinventorydepartment_name,
A.shoidea_duration, A.showidea_segment, A.showidea_PIC, A.showidea_concept,
A.showidea_isdisabled
FROM transaction_showidea AS A
LEFT OUTER JOIN view_showideainventory AS B on showinventorycategory_id = B.showinventorycategory_id
LEFT OUTER JOIN view_showideainventorydepartment AS C ON showinventorycategory_name = C.showinventorydepartment_id

Left outer join does not select all equipment notifs

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.

Postgresql - Conditional Join if data exist

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);

LEFT JOIN ON COALESCE(a, b, c) - very strange behavior

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.

Oracle: LEFT OUTER JOIN with using construct

I can't understand the usage of the using word. Can you explain me?
SELECT 1
FROM CONF_RAGGR_OPZTAR ropt
JOIN TAR_OPZIONI_TARIFFARIE OPT using (OPT_OPZIONE_TARIFFARIA_ID)
JOIN CONF_RAGGRUPPAMENTI_FORN rgf using (RGF_RAGGRUPPAMENTO_FORN_ID)
JOIN CONF_FORNITURE_REL_RAGG forg using (RGF_RAGGRUPPAMENTO_FORN_ID)
JOIN CONF_FORNITURE forn using (FORN_FORNITURA_ID)
LEFT JOIN (
select *
from CONF_ELEMENTI_FATTURABILI
where ELF_FLAG_ANN = 'N'
AND ELF_DATA_VER_FIN = TO_DATE('31/12/9999','DD/MM/YYYY')
) elf **using** (ROPT_RAGGR_OPZTAR_ID,COID_CONTRATTUARIO_ID,ROPT_DATA_INI,EDW_PARTITION)
-- LEFT OUTER JOIN TAR_VOCI_FATTURABILI vof
-- ON (elf.VOF_VOCE_FATTURABILE_ID = vof.VOF_VOCE_FATTURABILE_ID)
-- LEFT OUTER JOIN BASE_FASCE_ORARIE fas
-- ON (fas.FAS_FASCIA_ORARIA_ID = elf.FAS_FASCIA_ORARIA_ID)
WHERE FORN_FORNITURA_ID = 'QJlXmOFZPF3eAlAG'
ORDER BY elf.ELF_VERSIONE DESC;
The using keyword indicates that this is a natural join. This means that the column names on both side of the join are identical.
In your case this means that you will join both sides on ROPT_RAGGR_OPZTAR_ID, COID_CONTRATTUARIO_ID, ROPT_DATA_INI and EDW_PARTITION.