SQL - unable to group data getting error message - sql

Select
lot_loc.whse,
lot_loc.item,
item.Ufprofile,
item.UfColor,
item.Uflength,
item.unit_weight*Lot_loc.qty_on_hand 'QTY LBS. On Hand',
item.unit_weight*Lot_loc.qty_rsvd 'QTY LBS. Reserved',
item.UfQtyPerSkid,
lot_loc.loc,
Lot_loc.lot,
Lot_loc.qty_on_hand,
Lot_loc.qty_rsvd,
itemwhse.qty_reorder,
DateDiff(day, lot.Create_Date, GetDate())'Days Old',
lot_loc.CreateDate,
coitem.co_num,
coitem.co_line,
coitem.co_cust_num,
custaddr.name,
coitem.due_date,
item.description,
item.unit_weight*item.lot_size 'STD Run Size (Lbs.)'
from lot_loc_mst lot_loc
left outer join rsvd_inv_mst rsvd_inv on lot_loc.lot = rsvd_inv.lot
LEFT OUTER JOIN coitem_mst coitem ON coitem.co_num = rsvd_inv.ref_num
AND coitem.co_line = rsvd_inv.ref_line
AND coitem.item = rsvd_inv.item
left join custaddr_mst custaddr on coitem.co_cust_num = custaddr.cust_num and coitem.cust_seq = custaddr.cust_seq
Left join item_mst item on lot_loc.item = item.item
left join itemwhse_mst itemwhse on lot_loc.item = itemwhse.item
and lot_loc.whse = itemwhse.whse
inner join lot_mst lot on Lot_loc.lot = lot.lot
I need to group the data by qty lbs on hand. Not sure how to do it. I get a error message when i try to do it.
Error :Column 'lot_loc_mst.whse' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY
clause.

Just an example to try and help you with aggregation. I havent included every column but hopefully you can understand it enough to complete it yourself. If you want to group by a column all other columns must be either included in the group by clause as well or use an aggregate function such as SUM, MIN, MAX depending on what you want from that column. Otherwise SQL doesnt know what to do with these columns
e.g.
SELECT * FROM
(
Select
min(item.Uflength) AS [Item Length],
SUM(item.unit_weight*Lot_loc.qty_on_hand) [QTY LBS. On Hand],
SUM(item.unit_weight*Lot_loc.qty_rsvd) [QTY LBS. Reserved],
min(item.UfQtyPerSkid) AS [Qty Per Skid],
DateDiff(day, min(lot.Create_Date), GetDate())[Days Old],
min(item.description) AS [Item Description],
SUM(item.unit_weight*item.lot_size) [STD Run Size (Lbs.)]
from lot_loc_mst lot_loc
left outer join rsvd_inv_mst rsvd_inv on lot_loc.lot = rsvd_inv.lot
LEFT OUTER JOIN coitem_mst coitem ON coitem.co_num = rsvd_inv.ref_num
AND coitem.co_line = rsvd_inv.ref_line
AND coitem.item = rsvd_inv.item
left join custaddr_mst custaddr on coitem.co_cust_num = custaddr.cust_num and
coitem.cust_seq = custaddr.cust_seq
Left join item_mst item on lot_loc.item = item.item
left join itemwhse_mst itemwhse on lot_loc.item = itemwhse.item
and lot_loc.whse = itemwhse.whse
inner join lot_mst lot on Lot_loc.lot = lot.lot
) P
GROUP BY [QTY LBS. On Hand]

all the columns that are not being aggregated must be in the group by
for example
select a, b, sum(c)
from tab
group by a,b <-- maybe you are missing this part

Related

SUM function when using multiple tables not working right

Currently I'm using the following code:
SELECT psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
sum(ISNULL(Forecasts.schd_discr_qty, 0)) AS [Order Amount],
Product_Structure.pt_promo,
Forecasts.sod_nbr,
SUM(PaintSched.qty) AS schedamt
FROM MPA_Desc
LEFT OUTER JOIN psparcomp ON MPA_Desc.MPA_Number = psparcomp.ps_comp
LEFT OUTER JOIN Forecasts ON psparcomp.ps_par = Forecasts.sod_part
LEFT OUTER JOIN Product_Structure
ON psparcomp.ps_par = Product_Structure.pt_part
LEFT OUTER JOIN PaintSched ON MPA_Desc.MPAID = PaintSched.MPAID
WHERE Forecasts.schd_discr_qty > 0
GROUP BY psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
ISNULL(Forecasts.schd_discr_qty, 0),
Product_Structure.pt_promo,
Forecasts.sod_nbr
And these are my results:
I need the results to just show "MPA-0856" and a total summed for the order amount. It's pulling multiple times because from the forecasts table, the part numbers it's pulling are different part numbers, but these are painted parts that are used on multiple part numbers. I'm creating a report for our paint department here and they only need to see the total amount that they need to paint instead of amount by part number. I've tried this a couple of different ways on joins but nothing seems to work. Can anyone assist?
Just guessing: it seems that your GROUP BY clause shouldn't list this item:
ISNULL(Forecasts.schd_discr_qty, 0)
as that is part of the sums made.
Also, remove from group by and select any item that could possibly split your results among different rows (eg. colour, side, etc.)
Use a Window Function. (https://www.sqlshack.com/use-window-functions-sql-server/)
SELECT psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
sum(ISNULL(Forecasts.schd_discr_qty, 0)) OVER (PARTITION BY .... ) AS [Order Amount],
Product_Structure.pt_promo,
Forecasts.sod_nbr,
SUM(PaintSched.qty) OVER (PARTITION BY ..... ) AS schedamt
FROM MPA_Desc
LEFT OUTER JOIN psparcomp ON MPA_Desc.MPA_Number = psparcomp.ps_comp
LEFT OUTER JOIN Forecasts ON psparcomp.ps_par = Forecasts.sod_part
LEFT OUTER JOIN Product_Structure
ON psparcomp.ps_par = Product_Structure.pt_part
LEFT OUTER JOIN PaintSched ON MPA_Desc.MPAID = PaintSched.MPAID
WHERE Forecasts.schd_discr_qty > 0
GROUP BY psparcomp.ps_comp,
MPA_Desc.Side,
MPA_Desc.Color_Code,
MPA_Desc.Description,
ISNULL(Forecasts.schd_discr_qty, 0),
Product_Structure.pt_promo,
Forecasts.sod_nbr

LEFT JOIN in Query returning more records than desired

I'm working on an MS ACCESS query which should pull all available data from one main table (specified by FROM) and then joining three additional tables via LEFT JOIN. My issue is that the query is returning more records because of a one to many relationship.
Is there any way I can return only ONE record per line in the main table? Any help is greatly appreciated!! Thank you!
SELECT tbl_Item_PO.Item,
tbl_ItemSKUType.SKU,
tbl_Item_PO.[EX-FACTORY DATE],
tbl_Item_PO.[QTY PER SHIPMENT],
IIf(tbl_Item_PO.Item=Posted_Inv_Tran.Item And tbl_Item_PO.Whse=Posted_Inv_Tran.Whse And tbl_Item_PO.[ITR#]=Posted_Inv_Tran.[TRN Number],0,tbl_Item_PO.[QTY PER SHIPMENT]) AS QTY,
tbl_Item_PO.WHSE, tbl_WhseRegion.Region
FROM ((tbl_Item_PO
LEFT JOIN tbl_ItemSKUType ON tbl_Item_PO.item = tbl_ItemSKUType.Item)
LEFT JOIN tbl_WhseRegion ON tbl_Item_PO.WHSE = tbl_WhseRegion.Whse)
LEFT JOIN Posted_Inv_Tran ON (tbl_Item_PO.[ITR#] = Posted_Inv_Tran.[TRN Number]) AND (tbl_Item_PO.Whse = Posted_Inv_Tran.Whse) AND (tbl_Item_PO.Item = Posted_Inv_Tran.Item);
I've also tried creating sub-queries within the join statements that return only ONE record but I cannot get that to work either:
SELECT po.Item,
ist.SKU,
po.[EX-FACTORY DATE],
po.[QTY PER SHIPMENT],
IIf(po.Item=itr.Item And po.Whse=itr.Whse And po.[ITR#]=itr.[TRN Number],0,po.[QTY PER SHIPMENT]) AS QTY,
po.WHSE,
wh.Region
FROM ((tbl_Item_PO po
LEFT JOIN (select top 1 * from tbl_ItemSKUType
RIGHT JOIN tbl_Item_PO on tbl_ItemSKUType.Item = tbl_Item_PO.item
WHERE tbl_Item_PO.Item = tbl_ItemSKUType.Item)
ist ON po.item = ist.Item)
LEFT JOIN (select top 1 * from tbl_WhseRegion
RIGHT JOIN tbl_Item_PO on tbl_WhseRegion.Whse = tbl_Item_PO.Whse
WHERE tbl_Item_PO.whse = tbl_WhseRegion.Whse)
wh ON po.Whse = wh.Whse)
LEFT JOIN (select top 1 * from Posted_Inv_Tran
RIGHT JOIN tbl_Item_PO on Posted_Inv_Tran.[TRN Number] = tbl_Item_PO.[ITR#] AND Posted_Inv_Tran.Whse = tbl_Item_PO.Whse AND Posted_Inv_Tran.Item = tbl_Item_PO.Item
WHERE (tbl_Item_PO.[ITR#] = Posted_Inv_Tran.[TRN Number]) AND (tbl_Item_PO.Whse = Posted_Inv_Tran.Whse) AND (tbl_Item_PO.Item = Posted_Inv_Tran.Item))
it ON (po.[ITR#] = it.[TRN Number]) AND (po.Whse = it.Whse) AND (po.Item = it.Item);
You can achieve that with a group by clause. Make sure to list all fields in that clause which identify a line, and that all other expressions/fields you have in the select clause are aggregated with some aggregation function, like Min().
NB: Your IIf condition does not need to check all those fields, just one is enough: when one matches, all will match:
SELECT tbl_Item_PO.Item,
Min(tbl_ItemSKUType.SKU) AS SKU,
tbl_Item_PO.[EX-FACTORY DATE],
tbl_Item_PO.[QTY PER SHIPMENT],
Min(IIf(tbl_Item_PO.Item=Posted_Inv_Tran.Item, 0,
tbl_Item_PO.[QTY PER SHIPMENT])) AS QTY,
tbl_Item_PO.WHSE,
Min(tbl_WhseRegion.Region) AS Region
FROM ((tbl_Item_PO
LEFT JOIN tbl_ItemSKUType
ON tbl_Item_PO.item = tbl_ItemSKUType.Item)
LEFT JOIN tbl_WhseRegion
ON tbl_Item_PO.WHSE = tbl_WhseRegion.Whse)
LEFT JOIN Posted_Inv_Tran
ON (tbl_Item_PO.[ITR#] = Posted_Inv_Tran.[TRN Number])
AND (tbl_Item_PO.Whse = Posted_Inv_Tran.Whse)
AND (tbl_Item_PO.Item = Posted_Inv_Tran.Item)
GROUP BY tbl_Item_PO.Item,
tbl_Item_PO.[EX-FACTORY DATE],
tbl_Item_PO.[QTY PER SHIPMENT],
tbl_Item_PO.WHSE;

mssql query sum one field among other fields

I need to achieve something like this:
SELECT AttendDetails.Date,AttendDetails.AttendId, NameCode,PhoneNo,Patients.
[Next of Kin] as NextOfKin,Company,
ConsultFee,LabFee, XraFee as XrayFee, ECGFee,
AdmitFee,SUM(PresFee) AS TotalPresFee,MedFee,TheaterFee,ScanFee
FROM AttendDetails
LEFT JOIN Patients on AttendDetails.OPDNo = Patients.OPDNo
LEFT JOIN [Company list] on [Company list].AcNum = AttendDetails.GLOffset
LEFT JOIN ConsultDetails on AttendDetails.AttendId =
ConsultDetails.AttendId
LEFT JOIN LaboratoryDetails on AttendDetails.AttendId =
LaboratoryDetails.AttendId
LEFT JOIN XrayDetails on AttendDetails.AttendId = XrayDetails.AttendId
LEFT JOIN ECGDetails on AttendDetails.AttendId = ECGDetails.AttendId
LEFT JOIN AdmitDetails on AttendDetails.AttendId = AdmitDetails.AttendId
LEFT JOIN PrescripDetails on AttendDetails.AttendId =
PrescripDetails.AttendId
LEFT JOIN Medicals on AttendDetails.AttendId = Medicals.AttendId
LEFT JOIN TheaterDetails on AttendDetails.AttendId = TheaterDetails.AttendId
LEFT JOIN ScanDetails on AttendDetails.AttendId = ScanDetails.AttendId
WHERE AttendDetails.GLOffset = $P{company}
AND AttendDetails.Date BETWEEN $P{startDate} AND $P{endDate}
GROUP BY <something>
where one of the fields in the result is a SUM value. But i seem to not be getting the group by clause right. Or am I doing it all wrong??
During an aggregate query, all fields need to be either part of the GROUP BY clause or affected by an aggregate function. In this case, since you're only aggregating one column, your group by must be all remaining fields:
GROUP BY
AttendDetails.Date,
AttendDetails.AttendId,
NameCode,
PhoneNo,
Patients.[Next of Kin],
Company,
ConsultFee,
LabFee,
XraFee,
ECGFee,
AdmitFee,
MedFee,
TheaterFee,
ScanFee

Access query to include all records even if one field has missing data (is Null)

I am trying run a query to include all records. it is omitting records if one of the fields is null. Changing the "output all fields" in query properties to Yes brings in all fields but that is not what i need. i need all records. Here is my SQL query:
SELECT tblBOOK.Concat, tblBOOK.Owner1, tblBOOK.Owner2,
tblIndustry.[Industry Name], tblOwner1.Points, tblOwner2.Points,
tblIndustry.[Industry Points], tblBOOK.FILE, tblBOOK.SCORE,
tblFILE.Points, tblSCORE.Points, tblBOOK.Risk, tblRisk.Points,
[tblOwner1]![Points]+[tblOwner2]![Points]+[Industry Points]+
[tblFILE]! [Points]+[tblSCORE]![Points]+[tblRisk]![Points]
AS TtlPoints
FROM tblRisk
INNER JOIN (tblSCORE
INNER JOIN (tblFILE
INNER JOIN ((tblOwner1
INNER JOIN (tblOwner2
INNER JOIN tblBOOK
ON (tblOwner2.Secondary = tblBOOK.Owner2)
AND (tblOwner2.Primary = tblBOOK.Owner1))
ON tblOwner1.Primary = tblOwner2.Primary)
INNER JOIN tblIndustry
ON tblBOOK.Industry = tblIndustry.[Industry Name])
ON tblFILE.Score = tblBOOK.FILE)
ON tblSCORE.Score = tblBOOK.SCORE)
ON tblRisk.Factor = tblBOOK.Risk;
I also tried to add "IsNull" to the criteria and then in returns no records.
I needed to change these from INNER JOINS to LEFT JOINS
SELECT tblBOOK.Concat, tblIndustry.[Industry Name],tblIndustry.[Industry Points],
tblOwner1.Primary, tblOwner1.Points, tblFILE.Score, tblFILE.Points, tblCARD.Score,
tblCARD.Points, tblRisk.Factor, tblRisk.Points,
[Industry Points]+[tblOwner1]![Points]+[tblFILE]![Points]+[tblCARD]![Points]+
[tblRisk]![Points]
AS TotalPoints
FROM ((((tblBOOK
LEFT JOIN tblIndustry ON tblBOOK.Industry = tblIndustry.[Industry Name])
LEFT JOIN tblOwner1 ON tblBOOK.Owner1 = tblOwner1.Primary)
LEFT JOIN tblFILE ON tblBOOK.CSS = tblFILE.Score)
LEFT JOIN tblCARD ON tblBOOK.CARD = tblCARD.Score)
LEFT JOIN tblRisk ON tblBOOK.Risk = tblRisk.Factor;

what is this code doing can not understand it

I am trying to figure out what a query is doing and I just do not understand why it would join its self to its self on multiple occassions highlighted bit is the piece i am talking about?
its the part that starts with the [SupplyStatusUpdated] = COALESCE( gas supply and gas supply history
USE [CRM];
SELECT gs.GasSupplyID,
[Account ID] = acc.AccountID,
[GMSReference] = cast(gms.SiteRefNum as varchar),
[AccountNumber] = cast(gms.AccountNum as varchar),
[Organisation Name] = prf.[Name] ,
con.DeclaredDate,
[Contract Date] = CAST(con.ContractDate AS DATE),
[Contract Version] = cv.Name,
[Contract Status] = cs.Name,
loa.ContractEndDate [LOA CED],
gs.CurrentSupplierEndDate [PrevSupplierEndDate],
loa.ContractEndDate,
con.StartDate,
[Supply Status] = gss.Name,
[SupplyStatusUpdated] = COALESCE(
(
SELECT TOP 1 MAX(gsh2.CreatedDate)
FROM GasSupply gs2
INNER JOIN GasSupplyHistory gsh2
ON gsh2.GasSupplyFK = gs2.GasSupplyID
WHERE gsh2.EventFK = 2
AND gsh2.Notes LIKE '%Gas Supply Status (%'
AND gsh2.GasSupplyFK = gs.GasSupplyID
GROUP BY gsh2.GasSupplyFK
),
(
SELECT TOP 1 MAX(gsh3.CreatedDate)
FROM GasSupplyHistory gsh3
INNER JOIN (
SELECT gsh4.GasSupplyFK, MAX(gsh4.EventFK) AS [MaxEvent]
FROM GasSupplyHistory gsh4
WHERE gsh4.GasSupplyFK = gs.GasSupplyID
GROUP BY gsh4.GasSupplyFK
HAVING MAX(gsh4.EventFK) = 1
) dt
ON dt.GasSupplyFK = gsh3.GasSupplyFK
)
),
[EAC] = gs.EstimatedAnnualConsumption,
[PreviousSupplier] = r.name,
[Branch] = b.name,
[LeadSource] = ls.name,
gs.UnitPrice,
gs.StandingCharge,
gs.WholesalePrice,
COALESCE(deal.weeknumber,DATEPART(ISOWK, con.[ContractDate])) AS [Week]
FROM acc.Account acc
INNER JOIN [Profile] prf
ON acc.ProfileFK = prf.ProfileID
INNER JOIN [Contract] con
ON acc.AccountID = con.AccountFK
INNER JOIN [loacontract] lo
ON lo.ContractFK = con.ContractID
LEFT join [LeadSource] ls
ON ls.LeadSourceID = con.LeadSourceFK
INNER JOIN [ContractStatus] cs
ON cs.ContractStatusID = con.ContractStatusFK
INNER JOIN [ContractVersion] cv
ON cv.ContractVersionID = con.ContractVersionFK
INNER JOIN GasSupply gs
ON gs.ContractFK = con.ContractID
INNER JOIN GasSupplyStatus gss
ON gss.GasSupplyStatusID = gs.GasSupplyStatusFK
LEFT JOIN Deal deal
ON deal.ContractFK = con.ContractID
OUTER APPLY GetGMSReferenceNumbers(con.ContractID) gms
LEFT JOIN Branch b
ON b.BranchID = deal.BranchFK
LEFT JOIN DealBroker bro
ON bro.DealFK = deal.DealID
AND bro.BrokerTypeFK = 36
LEFT JOIN Person p
ON p.PersonID = bro.EmployeeFK
LEFT JOIN Reseller r
ON r.ResellerID = gs.ResellerFK
LEFT JOIN (
SELECT l.contractfk,
MIN(l.contractenddate)[ContractEndDate]
FROM CRM.[contract].LOAContract l
GROUP BY l.ContractFK
) loa
ON loa.ContractFK = con.ContractID
WHERE acc.AccountID not in (
select AccountFK
from AccountOption
where OptionFK=9
)
AND cast(gms.SiteRefNum as varchar) IS NULL
COALESCE(Something, SomethingElse) says if the first argument is NULL, return the second argument (note that you can have more than 2 args and it'll just keep going down the list).
As such it's running the first sub-query, and if the result is NULL, returning the result of the second query. Why exactly is your business logic, which we can't answer :-)
(MSDN link on Coalesce)
COALESCE returns the first non-null value it finds, so if the GasSupply query returns a result it will use that: if that returns null it will see if the GasSupplyHistory query returns a result, and if so use that. If both queries return null then SupplyStatusUpdated will be null.
It joins to itself to get historical records from the same source as where it gets the current record.
Representation of historical data is is one common reason for using a BigData/NoSQL database instead of a SQL/Relational database.