How do I condition a HAVING query? - sql

I have the following query:
select ctc.sentencia ,count(lg.id_libro) as cantidad
from cat_tipo_sentencia as ctc
left join libro_gobierno as lg on lg.cod_tiposentencia = ctc.id_sentencia
left join expedientes as e on e.id_expedientes = lg.cod_expediente
GROUP BY ctc.sentencia
I want to count the records that are in "libro_gobierno" of "cat_tipo_sentencia", but when conditioned it does not show me those that have 0 records and when removing the condition if it shows them, how could I condition so that the results return those that do not have records?
-
this is the conditioned query
select ctc.sentencia ,count(lg.id_libro) as cantidad
from cat_tipo_sentencia as ctc
left join libro_gobierno as lg on lg.cod_tiposentencia = ctc.id_sentencia
left join expedientes as e on e.id_expedientes = lg.cod_expediente
where e.cod_distrito= 130
and e.cod_estado_pro=13
and ctc.id_sentencia in (1,8,10)
GROUP BY ctc.sentencia
and when trying to use "HAVING" I get an error since the conditions are not within the group
these are the data that throws me
sentencia1 1
but in my condition there are also other options but it does not show them to me because there are no records, and I would like it to return me similar to:
sentencia1 1
sentencia2 0
sentencia3 0
PD: Sorry for the English, I'm using translator :(

In a LEFT OUTER JOIN, if you filter the outer table in the WHERE clause, the results become the same as if you did an INNER join. Rows from the main table that don't have a match in the joined table are filtered off.
You can avoid this by filtering in the ON clause of your join, instead of in the WHERE clause.
SELECT
ctc.sentencia
,count(lg.id_libro) AS cantidad
FROM
cat_tipo_sentencia AS ctc
LEFT JOIN
libro_gobierno AS lg
ON lg.cod_tiposentencia = ctc.id_sentencia
LEFT JOIN
expedientes AS e
ON e.id_expedientes = lg.cod_expediente
AND e.cod_distrito = 130
AND e.cod_estado_pro = 13
WHERE
ctc.id_sentencia IN (1,8,10)
GROUP BY
ctc.sentencia
I tried to use common words. I hope this translates OK for you!

Related

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.

Including 0 in count does not work with extra where clause

In my current project, I have user groups with facilities assigned to them. What I need is to show the user group's name, it's department, it's description and number of facilities assigned to it. I somewhat have been able to achieve this as shown below:
Current "successful" result
The problem that I am facing now is when I add a where clause stating that facilities that have been deleted should NOT be included. Below is my SQL statement that produces the result above:
Statement to achieve result above
SELECT ug.usergroupname UserGroupName, dpt.deptname Department, ug.usergroupdesc UserGroupDesc, count(ugf.usergroupid) NumOFFacilities
FROM tblusergroup ug
LEFT JOIN tblusergroupfacilities ugf
ON ug.usergroupid = ugf.usergroupid
LEFT JOIN tbldepartment dpt
ON dpt.deptcode = ug.deptcode
LEFT JOIN tblfacility f
ON ugf.facilityid = f.facilityid
WHERE ug.isdeleted = 0
GROUP BY ug.usergroupname, dpt.deptname, ug.usergroupdesc
However, when I add the where clause to not include deleted facilities, it produces a whole other result:
Edited statement
SELECT ug.usergroupname UserGroupName, dpt.deptname Department, ug.usergroupdesc UserGroupDesc, count(ugf.usergroupid) NumOFFacilities
FROM tblusergroup ug
LEFT JOIN tblusergroupfacilities ugf
ON ug.usergroupid = ugf.usergroupid
LEFT JOIN tbldepartment dpt
ON dpt.deptcode = ug.deptcode
LEFT JOIN tblfacility f
ON ugf.facilityid = f.facilityid
WHERE ug.isdeleted = 0
AND f.isdeleted = 0 //<-------added clause
GROUP BY ug.usergroupname, dpt.deptname, ug.usergroupdesc
Changed result
Is there any way at all to achieve the results above excluding the deleted facilities? Any help would really be appreciated.
Nothing off the top of my head on how to do it in one query, but with a UNION it seems straightforward. Run each alone to understand what they provide:
-- Your "changed" query.
UNION -- or UNION ALL, look up the difference, cuz I forgot it.
-- Your original query.
HAVING count(ugf.usergroupid) = 0
A LEFT JOIN keeps all rows in the first table plus matching rows in the second. When there is no match, then the values returned are NULL. Your condition on f.isdeleted removes all NULL values, turning the LEFT JOIN into an INNER JOIN.
The solution is to put the condition in the ON clause:
SELECT ug.usergroupname UserGroupName, dpt.deptname Department, ug.usergroupdesc UserGroupDesc, count(ugf.usergroupid) NumOFFacilities
FROM tblusergroup ug LEFT JOIN
tblusergroupfacilities ugf
ON ug.usergroupid = ugf.usergroupid LEFT JOIN
tbldepartment dpt
ON dpt.deptcode = ug.deptcode LEFT JOIN
tblfacility f
ON ugf.facilityid = f.facilityid AND f.isdeleted = 0
WHERE ug.isdeleted = 0
GROUP BY ug.usergroupname, dpt.deptname, ug.usergroupdesc;
Note that conditions on the first table do belong in the WHERE clause.

Left outer join with 2 column missing some output rows

When I select all rows from table zvw_test it return 145 rows.
Table Customer_Class_Price have 160 rows.
When I try to join this 2 table with 2 condition it return 122 rows.
I don't understand why it not return all rows from zvw_test (145 rows)
becasue I use left outer join it should return all rows from left table.
Thank you.
SELECT zvw_test.Goods_ID,
zvw_test.Thai_Name,
zvw_test.UM,
zvw_test.CBal,
Customer_Class_Price.ListPrice
FROM zvw_test
LEFT OUTER JOIN
Customer_Class_Price ON zvw_test.Goods_ID = Customer_Class_Price.Goods_ID AND
zvw_test.UM = Customer_Class_Price.UM
WHERE (Customer_Class_Price.ClassCode = '444-666')
By putting one of your columns from the LEFT OUTER JOIN table in your WHERE clause, you have effectively turned it into an INNER JOIN. You need to move that up to the JOIN clause.
I had this problem before, I used a CTE to solve this, like:
WITH A AS
(
SELECT Customer_Class_Price.Goods_ID, Customer_Class_Price.UM, Customer_Class_Price.ListPrice
FROM Customer_Class_Price
WHERE Customer_Class_Price.ClassCode = '444-666'
)
SELECT zvw_test.Goods_ID, zvw_test.Thai_Name, zvw_test.UM, zvw_test.CBal, A.ListPrice
FROM zvw_test LEFT OUTER JOIN A
ON zvw_test.Goods_ID = A.Goods_ID AND zvw_test.UM = A.UM
You demand in your WHERE clause:
(Customer_Class_Price.ClassCode = '444-666')
Ergo you are not selecting rows where Customer_Class_Price.ClassCode IS NULL. Customer_Class_Price.ClassCode would be NULL if there is no corresponding row, but you are filtering those out explicitely.

SQL Server 2008R2 Full outer join not working

I am trying to run the below query
SELECT mr.AsofDate as date,
mr.FA,
mr.TPNL as tpnl,
mr.MPNL as mpnl,
mrf.tpnl as mrfTpnl,
mrf.cpnl as mrfCpnl
FROM vw_daily mr
FULL OUTER JOIN mrfeeddaily mrf
ON mr.FA = mrf.book and mr.AsofDate = mrf.AsOfDate
WHERE mr.AsofDate = '20141121'
But i end up getting only rows from the first View vw_daily and the columns from mrfeeddaily are NULL, doesn't Full join return all non matching rows as well ? what am i missing.
There is no common data between the view and the table.
Move the filter to ON condition
ON tells what are the rows to used for Joining but where clause filters the result of join.
Only matched rows in vw_daily table is going to have value in asofdate so the filtering the rows in Where clause is going to do implicit conversion from FULL OUTER JOIN to INNER JOIN
SELECT mr.asofdate AS date,
mr.fa,
mr.tpnl AS tpnl,
mr.mpnl AS mpnl,
mrf.tpnl AS mrfTpnl,
mrf.cpnl AS mrfCpnl
FROM vw_daily mr
FULL OUTER JOIN mrfeeddaily mrf
ON mr.fa = mrf.book
AND mr.asofdate = mrf.asofdate
AND mr.asofdate = '20141121'
Filter the condition in your join.
SELECT mr.AsofDate AS date, mr.FA, mr.TPNL AS tpnl, mr.MPNL AS mpnl, mrf.tpnl AS mrfTpnl, mrf.cpnl AS mrfCpnl
FROM vw_daily mr
FULL OUTER JOIN mrfeeddaily mrf ON mr.FA = mrf.book
AND mr.AsofDate = mrf.AsOfDate
AND mr.AsofDate = '20141121'

including a condition dynamically based on another condition

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.