SQL integer division returns 0 rows - sql

I am trying to create a calculated field called efficiency %. This is calculated by taking LaborDtl.LaborHrs minus Calculated_Shouldhavetaken divided by Calculated_Shouldhavetaken. When I run the query I get zero rows returned, but creating the calculated field without the division returns the difference as expected. I believe this is due to how division is treated in the server.
/*
* Disclaimer!!!
* This is not a real query being executed, but a simplified version for general vision.
* Executing it with any other tool may produce a different result.
*/
select
[LaborDtl].[JobNum] as [LaborDtl_JobNum],
[JobHead].[PartNum] as [JobHead_PartNum],
[LaborDtl].[EmployeeNum] as [LaborDtl_EmployeeNum],
[LaborDtl].[OpCode] as [LaborDtl_OpCode],
[JobHead].[ProdQty] as [JobHead_ProdQty],
(LaborDtl.LaborQty + LaborDtl.ScrapQty) as [Calculated_TotalQty],
[LaborDtl].[LaborHrs] as [LaborDtl_LaborHrs],
(TotalQty/ JobHead.ProdQty* LaborDtl.LaborHrs* 1.0) as [Calculated_Shouldhavetaken],
[LaborDtl].[ClockInDate] as [LaborDtl_ClockInDate],
((LaborDtl.LaborHrs- Shouldhavetaken)/ Shouldhavetaken) as [Calculated_effpercent]
from Erp.LaborDtl as LaborDtl
inner join Erp.JobOper as JobOper on
LaborDtl.Company = JobOper.Company
and LaborDtl.JobNum = JobOper.JobNum
and LaborDtl.AssemblySeq = JobOper.AssemblySeq
and LaborDtl.OprSeq = JobOper.OprSeq
inner join Erp.JobOpDtl as JobOpDtl on
JobOper.Company = JobOpDtl.Company
and JobOper.JobNum = JobOpDtl.JobNum
and JobOper.AssemblySeq = JobOpDtl.AssemblySeq
and JobOper.OprSeq = JobOpDtl.OprSeq
inner join Erp.JobHead as JobHead on
JobOpDtl.Company = JobHead.Company
and JobOpDtl.JobNum = JobHead.JobNum
where (LaborDtl.ClockInDate = dateadd (day, -1, Constants.Today))
Any guidance would be appreciated.
Thanks

It could be as you mentioned. Any chance you could encapsulate the query and do your calculation for the division part outside just to test it?
Try casting decimal around Shouldhavetaken
CAST(Shouldhavetaken AS DECIMAL(9,2))
or something like that. See if works.
Another test you can run is to hardcode an int as the divisor and hardcode a decimal and see if you get different results. / 2 or / 2.0

Related

Returns the percent column as the value 1 all over. How do I fix it?

I want to create a view that calculates percentage, but what I have done, it only returns the percent column as the value 1 all over. How do I fix it?
GO
CREATE VIEW vRejectedProductsByType AS
SELECT
DimProductType.ProductTypeName,
DimProductSubtype.ProductSubtypeName,
CONVERT(DECIMAL(5,4), ManufacturingFact.RejectedProducts * 100 / (ManufacturingFact.AcceptedProducts + ManufacturingFact.RejectedProducts)) AS PercentRejected,
CONVERT(INT, ManufacturingFact.AcceptedProducts + ManufacturingFact.RejectedProducts) AS TotalManufactured,
CONVERT(DATE, ManufacturingFact.DateOfManufacture) AS DateOfManufacture
FROM DimProduct
INNER JOIN DimProductSubtype
ON DimProduct.ProductSubtypeCode = DimProductSubtype.ProductSubtypeCode
INNER JOIN DimProductType
ON DimProductType.ProductTypeCode = DimProductSubtype.ProductTypeCode
INNER JOIN ManufacturingFact
ON DimProduct.ProductCode = ManufacturingFact.ProductCode;
GO
As others commented, here is the result. First, your long table names make for more difficult readability. By using alias names that closer match the table source, it becomes easier to read. For example DimProduct now has an alias "dp". DimProductSubType is "st" (for sub type), similar with t=type, mf=manufacturing fact.
Now, you had all those converts. If the data types are already integer, no need to convert an int to an int.
As for the date, that would be the only one that I MIGHT keep the convert( date, ) context IF that column were based on a date/time inclusive and you only wanted to see the date itself, otherwise, just leave the date alone.
Your percentage calculation, since you were dividing int by an int, it gave you an int. To fix, just turn one into a decimal or float as noted by multiplying by 100.0
SELECT
t.ProductTypeName,
st.ProductSubtypeName,
mf.RejectedProducts * 100.0 / (mf.AcceptedProducts + mf.RejectedProducts) PercentRejected,
mf.AcceptedProducts + mf.RejectedProducts TotalManufactured,
mf.DateOfManufacture
FROM
DimProduct dp
JOIN DimProductSubtype st
ON dp.ProductSubtypeCode = st.ProductSubtypeCode
JOIN DimProductType t
ON st.ProductTypeCode = t.ProductTypeCode
JOIN ManufacturingFact mf
ON dp.ProductCode = mf.ProductCode;
Finally, to ever see / sample multiplication impacts in the future, you could always just sample from the SQL command window area and do something like
select 37 / 40
vs
select 37.0 / 40
or
select 37 / 40.0
and you can immediately see what SQL is going to do based on the data types.

Query correctly returns calculations but returns null when multiplied together in a sum

I am trying to calculate the sum of two calculations multiplied together. Independently, the {Hours} and {Rate} calculations work just fine but when I multiply them together within a sum formula, they normally return a null. The exception is that they will return 0 if the rate is 0.
If anyone has an guidance, it would be appreciated. I would also love to know what I did wrong because I'm teaching myself this.
Select
SFLTX.BF2RDAT as {Date},
SFLTX.BF2DEPT as {Dept},
sum((SFLTX.BF2QTYG / HJOBDR.EDRUNS)) as {HOURS},
(RESRE.ABLABR * ((RESRE.ABBRDP + RESRE.ABBDVP)/100)) as {RATE},
sum((SFLTX.BF2QTYG / HJOBDR.EDRUNS) * (RESRE.ABLABR * ((RESRE.ABBRDP + RESRE.ABBDVP)/100))) as {ABS}
from SFLTX
join ERW.FCALPF on SFLTX.BF2RDAT = ERW.FCALPF.FDATE
join HJOBDR on SFLTX.BF2JOBN = HJOBDR.EDJOB# and SFLTX.BF2SEQN = HJOBDR.EDSEQ#
Join RESRE on SFLTX.BF2DEPT = RESRE.ABDEPT and SFLTX.BF2RESC = RESRE.ABRESC
where SFLTX.BF2RDAT > '1/1/2019' and (right(ERW.FCALPF.FYEAR,2) = ‘19’ and SFLTX.BF2CMODE = 'R')
group by SFLTX.BF2RDAT , SFLTX.BF2DEPT, (RESRE.ABLABR * ((RESRE.ABBRDP + RESRE.ABBDVP)/100))
I attached an image of the data output.
If any of the columns involved in any of the calculations contains NULL values, then the result of the calculation will likewise be NULL. Ensure that either all columns are defined as NOT NULL, or, use a CASE statement to convert any NULL value to 0 or 0.00 (unless you are going to be dividing by that column).

SQL Server - Need to SUM values in across multiple returned records

In the following query I am trying to get TotalQty to SUM across both the locations for item 6112040, but so far I have been unable to make this happen. I do need to keep both lines for 6112040 separate in order to capture the different location.
This query feeds into a Jasper ireport using something called Java.Groovy. Despite this, none of the PDFs printed yet have been either stylish or stained brown. Perhaps someone could address that issue as well, but this SUM issue takes priority
I know Gordon Linoff will get on in about an hour so maybe he can help.
DECLARE #receipt INT
SET #receipt = 20
SELECT
ent.WarehouseSku AS WarehouseSku,
ent.PalletId AS [ReceivedPallet],
ISNULL(inv.LocationName,'') AS [ActualLoc],
SUM(ISNULL(inv.Qty,0)) AS [LocationQty],
SUM(ISNULL(inv.Qty,0)) AS [TotalQty],
MAX(CAST(ent.ReceiptLineNumber AS INT)) AS [LineNumber],
MAX(ent.WarehouseLotReference) AS [WarehouseLot],
LEFT(SUM(ent.WeightExpected),7) AS [GrossWeight],
LEFT(SUM(inv.[Weight]),7) AS [NetWeight]
FROM WarehouseReceiptDetail AS det
INNER JOIN WarehouseReceiptDetailEntry AS ent
ON det.ReceiptNumber = ent.ReceiptNumber
AND det.FacilityName = ent.FacilityName
AND det.WarehouseName = ent.WarehouseName
AND det.ReceiptLineNumber = ent.ReceiptLineNumber
LEFT OUTER JOIN Inventory AS inv
ON inv.WarehouseName = det.WarehouseName
AND inv.FacilityName = det.FacilityName
AND inv.WarehouseSku = det.WarehouseSku
AND inv.CustomerLotReference = ent.CustomerLotReference
AND inv.LotReferenceOne = det.ReceiptNumber
AND ISNULL(ent.CaseId,'') = ISNULL(inv.CaseId,'')
WHERE
det.WarehouseName = $Warehouse
AND det.FacilityName = $Facility
AND det.ReceiptNumber = #receipt
GROUP BY
ent.PalletId
, ent.WarehouseSku
, inv.LocationName
, inv.Qty
, inv.LotReferenceOne
ORDER BY ent.WarehouseSku
The lines I need partially coalesced are 4 and 5 in the above return.
Create a second dataset with a subquery and join to that subquery - you can extrapolate from the following to apply to your situation:
First the Subquery:
SELECT
WarehouseSku,
SUM(Qty)
FROM
Inventory
GROUP BY
WarehouseSku
Now apply to your query - insert into the FROM clause:
...
LEFT JOIN (
SELECT
WarehouseSKU,
SUM(Qty)
FROM
Inventory
GROUP BY
WarehouseSKU
) AS TotalQty
ON Warehouse.WarehouseSku = TotalQty.WarehouseSku
Without seeing the actual schema DDL it is hard to know the exact cardinality, but I think this will point you in the right direction.

Sqlite subquery with multiple sums

I have a sqlite database and I need to perform some arithmetic in my sql to get the final amount. The thing is I am not certain how to go and achieve this, I'm pretty certain from what I've been reading its a subquery which I need to group by lineID (unique id in my db)
The fields I want to include in the calculation below are
el.material_cost1 * el.material_qty1
el.material_cost2 * el.material_qty2
el.material_cost3 * el.material_qty3
The query I currently have is below. It returns the value of my costs apart from the fields missing above. As I store the material costs individually, I can't work out how to do a subquery within my query to get the desired result.
SELECT sum(el.enquiry_cost1) + sum(el.enquiry_cost2) + sum(el.enquiry_cost3)
FROM estimate e
LEFT JOIN estimate_line el
ON e.estimateID=el.estimateID
WHERE e.projectID=7 AND el.optional='false'
Use of a LEFT JOIN instead of an [INNER] JOIN is pointless, as your WHERE condition filters out any rows that could have differed.
I think you're making this harder than it needs to be. In particular, nothing in your description makes me think you need a subquery. Instead, it looks like this query would be close to what you're after:
SELECT
sum(el.enquiry_cost1)
+ sum(el.enquiry_cost2)
+ sum(el.enquiry_cost3)
+ sum(el.material_cost1 * el.material_qty1)
+ sum(el.material_cost2 * el.material_qty2)
+ sum(el.material_cost3 * el.material_qty3)
AS total_costs,
FROM
estimate e
JOIN estimate_line el
ON e.estimateID = el.estimateID
WHERE e.projectID = 7 AND el.optional = 'false'

Why does my sql logic fail first time it runs but not second time?

I have this sql:
SELECT
sa.answertext
FROM dbo.tblsurveyanswer sa
INNER JOIN dbo.tblsurvey s
ON s.surveyid = sa.surveyid
INNER JOIN dbo.tblquestion q
ON q.questionid = sa.questionid
INNER JOIN dbo.tblshqscriteria c
ON c.shqscriteriaid = q.shqscriteriaid
INNER JOIN dbo.tblshqsdescription d
ON d.shqsdescriptionid = q.shqsdescriptionid
INNER JOIN dbo.tblrepairpercentage rp
ON rp.repairpercentageid = sa.repairpercentageid
WHERE
(c.shqscriteria = 'qwerty')
OR
(c.shqscriteria = 'zxcvb' AND ISNUMERIC(sa.answertext) = 1 AND CAST(sa.answertext AS float) < 5)
First time I execute it fails with "Error converting data type varchar to float."
Second time* I execute it succeeds - returning no rows because there are no 'qwerty' or 'zxcvb' shqscriteria
*actually sometimes I have to hit execute up to 8 times before I get the failure
The order in which predicates are evaluated in SQL Server is not guaranteed (and certainly not guaranteed to be from left to right).
So:
c.shqscriteria = 'zxcvb' AND ISNUMERIC(sa.answertext) = 1 AND CAST(sa.answertext AS float) < 5
It may attempt the CAST operation on a value for which ISNUMERIC() returns 0. The actual order in which the predicates are evaluated can vary for many different reasons - as you've discovered, the slightest thing can change it.
Also, ISNUMERIC is a mostly useless function. CAST('£' as float) will fail, but ISNUMERIC('£') is 1. It answers the question no-one has ever asked - "Can I convert this string into even just one of the numeric datatypes (I don't care which one)?"
The way to resolve this kind of issue is to split your query into two parts - the first of which selects appropriate data for conversion and stores the values in a (temp table/table variable), the second part actually performs the conversion. Or if you're on SQL Server 2012 or later, look into the TRY_ conversion functions:
c.shqscriteria = 'zxcvb' AND TRY_CAST(sa.answertext AS float) < 5
As long as you're not using aggregates, you should be able to rely on CASE's order of execution:
WHERE
...
OR
(
c.shqscriteria = 'zxcvb'
AND 5 > CASE WHEN ISNUMERIC(sa.answertext) = 1
THEN CAST(sa.answertext AS float)
ELSE 6
END
)
Note however that ISNUMERIC(col) = 1 does not always mean that col is eligible to be converted to a specific numeric type.