SQL Having Clause - sql

I'm trying to get a stored procedure to work using the following syntax:
select count(sl.Item_Number)
as NumOccurrences
from spv3SalesDocument as sd
left outer join spv3saleslineitem as sl on sd.Sales_Doc_Type = sl.Sales_Doc_Type and
sd.Sales_Doc_Num = sl.Sales_Doc_Num
where
sd.Sales_Doc_Type='ORDER' and
sd.Sales_Doc_Num='OREQP0000170' and
sl.Item_Number = 'MCN-USF'
group by
sl.Item_Number
having count (distinct sl.Item_Number) = 0
In this particular case when the criteria is not met the query returns no records and the 'count' is just blank. I need a 0 returned so that I can apply a condition instead of just nothing.
I'm guessing it is a fairly simple fix but beyond my simple brain capacity.
Any help is greatly appreciated.
Wally

First, having a specific where clause on sl defeats the purpose of the left outer join -- it bascially turns it into an inner join.
It sounds like you are trying to return 0 if there are no matches. I'm a T-SQL programmer, so I don't know if this will be meaningful in other flavors... and I don't know enough about the context for this query, but it sounds like you are trying to use this query for branching in an IF statement... perhaps this will help you on your way, even if it is not quite what you're looking for...
IF NOT EXISTS (SELECT 1 FROM spv3SalesDocument as sd
INNER JOINs pv3saleslineitem as sl on sd.Sales_Doc_Type = sl.Sales_Doc_Type
and sd.Sales_Doc_Num = sl.Sales_Doc_Num
WHERE sd.Sales_Doc_Type='ORDER'
and sd.Sales_Doc_Num='OREQP0000170'
and sl.Item_Number = 'MCN-USF')
BEGIN
-- Do something...
END

I didn't test these but off the top of my head give them a try:
select ISNULL(count(sl.Item_Number), 0) as NumOccurrences
If that one doesn't work, try this one:
select
CASE count(sl.Item_Number)
WHEN NULL THEN 0
WHEN '' THEN 0
ELSE count(sl.Item_Number)
END as NumOccurrences

This combination of group by and having looks pretty suspicious:
group by sl.Item_Number
having count (distinct sl.Item_Number) = 0
I'd expect this having condition to approve only groups were Item_Number is null.
To always return a row, use a union. For example:
select name, count(*) as CustomerCount
from customers
group by
name
having count(*) > 1
union all
select 'No one found!', 0
where not exists
(
select *
from customers
group by
name
having count(*) > 1
)

Related

SQL aggregation updates for some but not others

I am running this query which should take the sum of an amount from a table and if it <= 0, update the status of a different table from Active to Deactive. The query updates some values but not others. I have isolated to one observation where there are 3 payments that total 0 where it does not work.(123456789) What could be happening here? I am using sql query in Microsoft Access. Thank you.
UPDATE tbl_MASTER INNER JOIN tbl_Payments ON tbl_MASTER.DeviceID = tbl_Payments.DeviceID SET tbl_MASTER.ActiveDeactive = "DeActive"
WHERE tbl_Payments.Amount=(SELECT SUM(tbl_Payments.Amount) <= 0 FROM tbl_Payments) AND tbl__MASTER = '123456789';
Your query doesn't really make a lot of sense, to be honest. Where you have tbl_Payments.Amount=(SELECT SUM(tbl_Payments.Amount) <= 0 FROM tbl_Payments), that sub-query will just be summing up the "Amount" of every record in the table, regardless of which DeviceID. Plus, you're looking for one record in tbl_Payments table where the Amount = the sum of all of the Amounts in tbl_Payments??
I'd suggest that your query probably needs to be something more like this:
UPDATE tbl_MASTER SET tbl_MASTER.ActiveDeactive = "DeActive"
WHERE (SELECT SUM(tbl_Payments.Amount) FROM tbl_Payments WHERE tbl_Payments.DeviceID = tbl_MASTER.DeviceID) <= 0 AND tbl__MASTER = '123456789';
Currently, the subquery does not correlate specific IDs to outer query and also you specify <= 0 inside subquery's SELECT clause. Consider adjusting for IN clause with logic in a conditional HAVING and use table aliases to distinguish same named tables.
UPDATE tbl_MASTER AS m
INNER JOIN tbl_Payments AS p
ON m.DeviceID = p.DeviceID
SET m.ActiveDeactive = 'DeActive'
WHERE sub_p.DeviceID IN (
SELECT sub_p.DevideID
FROM tbl_Payments AS sub_p
GROUP BY sub_p.DeviceID
HAVING SUM(sub_p.Amount) <= 0
)

Join SQL Server Showing Duplicate Row

I want to ask something about joining query. I have a query like this:
SELECT b.compilecodingid,
a.subjobfamily,
b.position,
b.nocoding,
( CASE
WHEN (SELECT Count(0)
FROM trlspbia
WHERE learningsystemid = a.learningsystemid
AND compilecodingid = b.compilecodingid
AND moduleid = '2018081616230361362303614'
AND learningroadmap = 'Basic') > 0 THEN 1
ELSE 0
END ) AS CountPickPBIA
FROM trlsplanning a,
trcompilecodingheader b
WHERE a.learningsystemid = b.learningsystemid
AND a.position = b.position
AND a.learningsystemid = '2018081513283162000000001'
order by CountPickPBIA desc
I know it's because Column Position on Table TrLsPlanning has more than 1 data,
Anyone can help me to find the solution?
Thank you.
The simplest solution is probably select distinct:
SELECT cch.compilecodingid, p.subjobfamily, cch.position, cch.nocoding,
(CASE WHEN EXISTS (SELECT 1
FROM trlspbia s
WHERE s.learningsystemid = p.learningsystemid AND
s.compilecodingid = ccb.compilecodingid AND
s.moduleid = '2018081616230361362303614' AND
s.learningroadmap = 'Basic'
)
THEN 1
ELSE 0
END) AS CountPickPBIA
FROM trlsplanning p JOIN
trcompilecodingheader cch
ON p.learningsystemid = cch.learningsystemid AND
p.position = cch.position
WHERE p.learningsystemid = '2018081513283162000000001'
ORDER BY CountPickPBIA DESC;
SELECT DISTINCT incurs its own overhead. But without more information about the structure and contents of the table, this is the simplest solution.
Note other changes in the query:
Table aliases are abbreviations for table names, rather than being arbitrary letters.
The JOIN syntax is fixed, to use modern, proper, and standard JOIN/ON.
All columns are qualified with the table alias, particularly those in the correlated subqueries.
The subquery uses EXISTS rather than COUNT(*). This is both more efficient and it probably better expresses the logic you want.

SQL conditional for a field using multiple subqueries as cases

I am using Proc SQL, but this question should be relevant for all SQL variants. I am trying to populate a field BruceDPOtest with values from two subqueries with if the first query results in blanks--CASE WHEN BruceDPO = INPUT("", 8.) --it fills that blank with another subquery's BruceDPO value:
THEN (
SELECT SUM(PART_QTY) FROM RSCCParts LEFT JOIN DPO.DPO_PART_ORD_HST AS Total
ON RSCCParts.PartID = STRIP(Total.PART_NO_ID)
WHERE PUT(PROC_DT, YY.) LIKE '%2016%' GROUP BY PART_NO_ID) ELSE BruceDPO END
For example, the first query gives the following results;
Part DPO
1234 100
1235
The second subquery that references data that can populate the second row is run to get:
Part DPO
1234 100
1235 999
Here is the full code:
PROC SQL;
CREATE VIEW DPOMergeView AS(SELECT *,
CASE
WHEN BruceDPO = INPUT("", 8.) THEN (
SELECT SUM(PART_QTY) FROM RSCCParts LEFT JOIN DPO.DPO_PART_ORD_HST AS Total
ON RSCCParts.PartID = STRIP(Total.PART_NO_ID)
WHERE PUT(PROC_DT, YY.) LIKE '%2016%' GROUP BY PART_NO_ID)
ELSE BruceDPO
END
AS BruceDPOtest
FROM
RSCCParts
LEFT JOIN (SELECT RSCCParts.PartID AS BrucePartID, BruceDPO, Year
FROM RSCCParts
LEFT JOIN
(SELECT PART_NO_ID AS PartNumber, SUM(PART_QTY) AS BruceDPO, STRIP(YR) AS Year
FROM
DPO.DPO_PART_HST_MAIN
WHERE YR = '2016'
GROUP BY PartNumber, Year) AS FQuery
ON
RSCCParts.PartID = STRIP(FQuery.PartNumber)) AS B
ON RSCCParts.PartID = B.BrucePartID);
QUIT;
As I run this query, it gets stuck on DATA Step and after 30 minutes, I stopped the query. Am I doing this correctly? If there is a better way to do this please let me know!
Normally I avoid correlated subqueries in SQL since it just makes it feel like you are trying to process the data record by record instead of by combining sets. But if you did what to use syntax like
case when (x) then (sub query result) else variable_name end
then the subquery needs to return only one value. Your query
SELECT SUM(PART_QTY)
FROM RSCCParts LEFT JOIN DPO.DPO_PART_ORD_HST AS Total
ON RSCCParts.PartID = STRIP(Total.PART_NO_ID)
WHERE PUT(PROC_DT, YY.) LIKE '%2016%'
GROUP BY PART_NO_ID
looks like it will return multiple observations since you are using a GROUP BY clause.
Shouldn't that subquery look more like
SELECT SUM(Total.PART_QTY)
FROM DPO.DPO_PART_ORD_HST AS Total
WHERE RSCCParts.PartID = STRIP(Total.PART_NO_ID)
AND PUT(PROC_DT, YY.) LIKE '%2016%'
Your query has multiple references to RSCCPARTS table so you might need to introduce an alias to each so that you can clarify which one you want to use to get PARTID from to match to PART_NO_ID.

sqlite extra column with 1 and 0 if record exists in related table or not

I am not so good at SQL, so I have the following tables
Stuff
and
Specialty
Let's say, the worker with name 'Bob' has two specialties. How could I get the specialty table with an extra column (let's say count) which has 1 if the record exists in Stuff and 0 otherwise.
I would like to ask if there is any way to cast a query
that returns a result for Bob as shown below?
Any suggestions would be very helpful. Thank you in advance.
(I am not sure about the title. Please do suggest if you have a better idea!)
I would be inclined to do this with a case and exists:
select sp.*,
(case when exists (select 1
from stuff s
where s.surname = 'Bob' and
s.speciality_code = sp.speciality_code
)
then 1 else 0
end) as BobHas
from specialty sp;
Use Left Outer join with Null check. Try this.
SELECT sp.specialitycode,
sp.description,
CASE
WHEN st.specialitycode IS NULL THEN 0
ELSE 1
END AS count
FROM speciality sp
LEFT OUTER JOIN (SELECT specialitycode
FROM stuff
WHERE surname = 'Bob') st
ON sp.specialitycode = st.specialitycode

How do I INSERT INTO where many fields have their own Select Statements?

I created a table and i am in the process of inserting rows from another table into it. However, some of these rows require joins from other tables. To my knowledge, this means using a subquery select statement in the statement. the problem is subqueries only return one result, where i may have many. I am wanting to return a -1 where no records exists. Here is an example i am using but it is not working:
INSERT INTO [BDW_ReportPrototype].[dbo].[CustomerCreditFact]
( [MortgageDimID]
,[LeaseDimID]
,[OREODimID]
,[OfficerTypeDimID] )
SELECT
--[MortgageDimID]
-2
--LeaseDimID
,-2
--OREODimID
,-2
,CASE WHEN OfficerTypeDimID IS NULL THEN -1 ELSE OfficerTypeDimID END
FROM Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN ERMA..OfficerTypeDim OTD on OTD.OfficerNum = LCD.OFFICER
FROM dbo.Staging_FDB_LN_CPDM_Daily
Try this sql statement
SELECT CASE WHEN OfficerTypeDimID IS NULL THEN -1 ELSE OfficerTypeDimID END
FROM Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN ERMA..OfficerTypeDim OTD on OTD.OfficerNum = LCD.OFFICER
I would rework your query like the following.
First of all, use a LEFT OUTER JOIN in your query instead of the subqueries. This type of join says a row might exist in the "other" table but it might not but I want a row back regardless.
Now that you know you'll have all your rows, you'll want to see if there is a value there or not. Use the shorthand and easier to maintain check via the coalesce function. It basically is a list of values (column names, variables or hard coded values) and the optimizer will pick the first non-null value from the list and use it. Here we supply -1 for your query
INSERT INTO
[BDW_ReportPrototype].[dbo].[CustomerCreditFact]
(
[OfficerTypeDimID]
)
SELECT
-- coalesce returns the first non-null value
COALESCE(OTD.OfficerTypeDimID, -1) AS OfficerTypeDimID
FROM
dbo.Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN
ERMA..OfficerTypeDim OTD
ON OTD.OfficerNum = LCD.OFFICER
maybe something along these lines...
INSERT INTO [BDW_ReportPrototype].[dbo].[CustomerCreditFact]
([OfficerTypeDimID])
Select OfficerTypeDimID
from ERMA..OfficerTypeDim OTD
inner JOIN Staging_FDB_LN_CPDM_Daily LCD
on OTD.OfficerNum = LCD.OFFICER
UNION ALL
SELECT -1
FROM dbo.Staging_FDB_LN_CPDM_Daily LCD
WHERE NOT EXISTS
(
Select OfficerTypeDimID from ERMA..OfficerTypeDim
OTD
WHERE
OTD.OfficerNum = LCD.OFFICER
)