TSQL: SUM not working like i thought it would - sql-server

I have the following query:
SELECT
a.Name,
ISNULL(CAST(sum((b.qty * b.unit_rate)* b.Eng_RPQ )/100 AS DECIMAL(8,1)),0) AS [EngHours],
SUM(BR.BlendedRate)
FROM
Activity_Details b
INNER JOIN
Activity c on b.activity_id = c.id
INNER JOIN
Project p on p.id = c.project_id
RIGHT OUTER JOIN
Discipline a on c.discipline_id = a.id
INNER JOIN
(SELECT
a.Name, c.id,
CAST(f.POH * (d.HourlyRate * (1-(r.Discount/100))/100) AS DECIMAL(8,2)) AS BlendedRate
FROM
Activity_Details b
INNER JOIN
Activity c on b.activity_id = c.id
INNER JOIN
Team f on f.activity_id = c.id
INNER JOIN
SOF_Details d on d.id = f.sof_detail_id
INNER JOIN
Project p on p.id = c.project_id
INNER JOIN
Rate r on r.projectid = p.id
INNER JOIN
Teammate_Type tt on tt.id = f.team_type_id
RIGHT OUTER JOIN
Discipline a on c.discipline_id = a.id
GROUP BY
a.Name, c.id, f.POH, d.HourlyRate, r.Discount) AS BR ON BR.id = c.id
GROUP BY
a.Name
ORDER BY
a.Name
Which yields:
Name EngHours BlendedRate
Architechtural 80.8 38.48
Architechtural 80.8 55.33
Architechtural 80.8 55.40
I want to SUM this BlendedRate and ROUND it but if i try SUM(BR.BlendedRate) to the SELECT and remove the BR.BlendedRate in the GROUP BY
I get:
Name EngHours BlendedRate
Architechtural 242.3 895.26
I was expecting BlendedRate to equal 149.21
Any idea what i am doing wrong?

unable to comment due to reputation. It is a crude solution, but your code is returning duplicated (seemingly 6) records. The code should be fixed elsewhere, but without sample data it is difficult. In the mean time a crude solution would be to add a distinct clause to the sum function
SUM( DISTINCT BR.BlendedRate)

Related

SQL Query joining parent table with several children rows into one row

I'm trying to implement query to take setups information from database where one setup has link to several items types: Controller, platform and KVM device.
This way:
Rack
|
Setup
/ | \
controller Platform KVM
Connections between parent and children are stored in another table.
I tried the bellow query, but I got setup children in separated rows.
How can I improve query to solve this?
Query:
select R.Id as Rack_Id,
S.Id,C.Id as Setup_Id,
P.Id as Platform_Id,
K.Id as KVM_Id,
R.Capacity, R.[Rack location],
S.[Location in Rack], C.[Controller IP], P.ISMP, P.Platform
From #Racks R join LinksAre LR on LR.SourceId = R.Id
join #Setups S on LR.TargetId=S.Id
left join LinksAre LS on LS.SourceId = S.Id
left join #KVMs K on LS.TargetID = K.Id
left join #Controllers C on LS.TargetId=C.Id
left join #Platforms P on LS.TargetId = P.Id
order by R.Id, S.Id
Thanks!
Think you might need a subquery:
select R.Id as Rack_Id,
S.Id,C.Id as Setup_Id,
P.Id as Platform_Id,
K.Id as KVM_Id,
R.Capacity, R.[Rack location],
( SELECT S.[Location in Rack] FROM #Setups S
WHERE S.ID = LR.TargetId) AS ColumnA,
C.[Controller IP],
P.ISMP, P.Platform
From #Racks R join LinksAre LR on LR.SourceId = R.Id
left join LinksAre LS on LS.SourceId = S.Id
left join #KVMs K on LS.TargetID = K.Id
left join #Controllers C on LS.TargetId=C.Id
left join #Platforms P on LS.TargetId = P.Id
order by R.Id, S.Id

SQL: No Sub-Query but only Joins

I am trying to find an alternative to this query where no sub-select is present but only joins (left, right, inner etc).
select count(SC.NUMBER_C)
from FNQP2PORTAL.SA.SEC_CAS SC
where SC.NUMBER_C not in (
select E.Reference from
FNQP2HQ.dbo.Entities E
join FNQP2HQ.dbo.Classes C on C.ID = E.ClassID
where C.Reference = 'Assembly case')
So, it should be something like...
select count(SC.NUMBER_C)
from FNQP2PORTAL.SA.SEC_CAS SC
left join FNQP2HQ.dbo.Entities E on E.Reference = SC.NUMBER_C and E.Reference IS NULL
inner join FNQP2HQ.dbo.Classes C on C.ID = E.ClassID and C.Reference = 'Assembly case'
Can somebody help me here?
The queries you posted are very different. One is inclusive (where SC.NUMBER_C IN.... - and the other is exclusive (left outer join where E.Reference is NULL). Because of these completely different queries, it's unclear what you're trying to do.
This is how you would accomplish your first query with a join instead of the subquery.
SELECT COUNT(SC.NUMBER_C)
FROM FNQP2PORTAL.SA.SEC_CAS SC
JOIN FNQP2HQ.dbo.Entities E
ON SC.NUMBER_C = E.Reference
JOIN FNQP2HQ.dbo.Classes C
ON C.ID = E.ClassID
WHERE C.Reference = 'Assembly Case'
EDIT:
You need to use a subquery and NOT IN to get what you're asking for in your comment. You can't only use joins.
SELECT COUNT(SC.NUMBER_C)
FROM FNQP2PORTAL.SA.SEC_CAS SC
WHERE SC.NUMBER_C NOT IN
(
SELECT E.Reference
FROM FNQP2HQ.dbo.Entities E
JOIN FNQP2HQ.dbo.Classes C
ON C.ID = E.ClassID
WHERE C.Reference = 'Assembly Case'
)
select count(SC.NUMBER_C)
from FNQP2PORTAL.SA.SEC_CAS SC
INNER JOIN FNQP2HQ.dbo.Entities E on SC.NUMBER_C = E.Reference
INNER JOIN FNQP2HQ.dbo.Classes C on C.ID = E.ClassID
where C.Reference = 'Assembly case'
One reason people use the WHERE IN logic is because of duplicates being returned via join. So in this case moving the logic to inner joins could result in the count inflating. Here's how you would work around that:
select count(SC.NUMBER_C)
from FNQP2PORTAL.SA.SEC_CAS SC
inner join
(
select distinct E.Reference
from FNQP2HQ.dbo.Entities E
join FNQP2HQ.dbo.Classes C on C.ID = E.ClassID
where C.Reference = 'Assembly case'
) as b
on b.reference = sc.NUMBER_C
Try the below code , it may throw error as you have not share the sample data with us. But you should use exists clause.
SELECT COUNT(SC.NUMBER_C)
FROM FNQP2PORTAL.SA.SEC_CAS SC,
FNQP2HQ.dbo.Classes C,
FNQP2HQ.dbo.Entities E
WHERE C.ID = E.ClassID
AND C.Reference = 'Assembly Case'
and not exists(
select 1 from FNQP2HQ.dbo.Entities E1
ON SC.NUMBER_C = E1.Reference)

Select only columns from joined tables from CTE

The following is my CTE:
;WITH CTE AS
(SELECT O.*, E.Num, E.Amount
FROM OData O
INNER JOIN Equip E
ON O.Name = E.Name)
SELECT * FROM CTE -- gives results I want to join to
The following is the query that I want to SELECT from (and only use this SELECT statement for my query results:
SELECT
MU.Type
,MU.Num
,MU.MTBUR
,MF.MTBF
,MU.Hours
,MF.Hours
FROM
MUType_Stage MU
INNER JOIN
MFType_Stage MF
ON
MU.Type = MF.Type
AND
MU.Num = MF.Num
-- Need do JOIN to CTE right here
INNER JOIN
Status_STAGE S
ON
MU.Nu = S.Part
LEFT OUTER JOIN
RCN N
ON
N.Name = R.Part
LEFT OUTER JOIN
Repair RR
ON
R.ACSS_Name = RR.Name
So basically I need to JOIN to the CTE inside the SELECT query in which I want the results.
OR ALTERNATIVELY Uses this select statement to join to the CTE but only what the selected columns from the second select statement
Try this syntax
WITH CTE
AS (SELECT O.*,
E.Num,
E.Amount
FROM OData O
INNER JOIN Equip E
ON O.Name = E.Name)
SELECT MU.Type,
MU.Num,
MU.MTBUR,
MF.MTBF,
MU.Hours,
MF.Hours
FROM MUType_Stage MU
INNER JOIN MFByACType_Stage MF
ON MU.Type = MF.Type
AND MU.Num = MF.Num
INNER JOIN CTE C --- JOIN HERE as like other tables
ON C.Num = MF.Num
INNER JOIN Status_STAGE S
ON MU.Nu = S.Part
LEFT OUTER JOIN RCN N
ON N.Name = R.Part
LEFT OUTER JOIN Repair RR
ON R.ACSS_Name = RR.Name

Use a calculated column in a where clause

I'm trying to use a calculated column in a where clause.
I've trying everything from CROSS APPLY, to sub-query select but it does not give me the anything near what I need.
My query so far:
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
WHERE Sales > 100
GROUP BY p.Code, c.AccountNumber, Sales
This does not work, as 'Sales' is an invalid column
Using Derived Columns in a predicate
You'll need to wrap the inner query in a derived table or CTE in order to be able to use derived columns in the WHERE clause (Also, note SUM() is specified just once, using the results of the multiplication):
SELECT x.Code, x.AccountNumber, x.Sales
FROM
(
SELECT p.Code, c.AccountNumber, SUM(p.UnitPrice *od.QtyShipped) AS Sales
FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber
) AS x
WHERE x.Sales > 100;
Repeating the Derived Column in a HAVING clause
As per #Jonny's comment, the other way is not to DRY up the calculated column, but to instead repeat the calculation. Use HAVING instead of WHERE after a GROUP BY has been applied.
SELECT p.Code, c.AccountNumber, SUM(p.UnitPrice *od.QtyShipped) AS Sales
FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber
HAVING SUM(p.UnitPrice * od.QtyShipped) > 100;
In either case, as per comments below, note that the calculated expression is SUM(p.UnitPrice * od.QtyShipped) and not SUM(p.UnitPrice) * SUM(od.QtyShipped).
You can use the common table expression for this
;WITH CTE AS
(
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber, Sale
)
SELECT *
FROM CTE WHERE CTE.Sales>100
If it's a calculated column you can use "HAVING".
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber, Sales
HAVING SALES > 100;

SQL Server Nested Query Performance

I need some help writing this query for SQL Server. The nested part makes this query take almost a minute to run on 27,000 records. I think it needs a temp table, but I have not done this before. Can someone give me an idea how I might do this?
SELECT
r.ID,
r.CloseDate,
r.RepairOrderStatus 'Repair Status',
p.PartNumber ModInPN,
p.PartDescription ModInDesc,
pr.RMANumber,
c.FullName OpsTech,
(SELECT COUNT (*)
FROM dbo.TestPartsReplaced tpr
WHERE tpr.RepairID = r.ID) Qty
FROM dbo.RepairTicket r LEFT JOIN dbo.Parts p ON r.ModuleInPartID = p.ID
LEFT JOIN dbo.PartReturn pr ON r.PartReturnID = pr.ID
LEFT JOIN dbo.Contact c ON c.ID = r.ContactTechID
Try this....
SELECT
r.ID,
r.CloseDate,
r.RepairOrderStatus 'Repair Status',
p.PartNumber ModInPN,
p.PartDescription ModInDesc,
pr.RMANumber,
c.FullName OpsTech,
Qty.[Count] AS Quantity
FROM dbo.RepairTicket r LEFT JOIN dbo.Parts p ON r.ModuleInPartID = p.ID
LEFT JOIN dbo.PartReturn pr ON r.PartReturnID = pr.ID
LEFT JOIN dbo.Contact c ON c.ID = r.ContactTechID
LEFT JOIN (SELECT RepairID , COUNT (*) AS [Count]
FROM dbo.TestPartsReplaced
GROUP BY RepairID) Qty ON Qty.RepairID = r.ID

Resources