SQL using SUM and INNER JOIN issue - sql

I get this error when I try to execute the query shown below
Column 'dbo.Stock_Purchase.Supplier_ID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Query:
SELECT
dbo.Stock_Purchase.*, dbo.Stock_Purchase_Details.*,
dbo.Supplier.*,
SUM(Stock_Purchase_Details.Discount) AS totaldis
FROM
dbo.Stock_Purchase
INNER JOIN
dbo.Stock_Purchase_Details ON dbo.Stock_Purchase.Purchase_ID = dbo.Stock_Purchase_Details.Purchase_ID
INNER JOIN
dbo.Supplier ON dbo.Stock_Purchase.Supplier_ID = dbo.Supplier.Supplier_ID
GROUP BY
Stock_Purchase.Purchase_ID

You can only include the column in the GROUP BY as a "bare" column in the SELECT. So:
SELECT p.Purchase_ID, sum(pd.Discount) as totaldis
FROM dbo.Stock_Purchase p INNER JOIN
dbo.Stock_Purchase_Details pd
ON p.Purchase_ID = pd.Purchase_ID INNER JOIN
dbo.Supplier s
ON p.Supplier_ID = s.Supplier_ID
GROUP BY p.Purchase_ID ;
Also notice how table aliases make the query easier to read, write, and understand.
If you do want all the details, you can use window functions:
SELECT p.*, pd.*, s.*,
SUM(pd.Discount) OVER (PARTITION BY p.Purchase_ID) as totaldis
FROM dbo.Stock_Purchase p INNER JOIN
dbo.Stock_Purchase_Details pd
ON p.Purchase_ID = pd.Purchase_ID INNER JOIN
dbo.Supplier s
ON p.Supplier_ID = s.Supplier_ID;

Related

Why am I getting ORA-00979: not a GROUP BY expression error?

Just a disclaimer, I'm very new to SQL... so please go easy on me. This is the script I have so far, and for the most part it's working, I'm just having a problem trying to only get the most recent DTTM record. What's wrong with my group by expression?
select
i.item_name,
i.description,
MAX(w.LAST_UPDATED_DTTM)as MOST_RECENT_DTTM,
w.last_updated_source,
w.tc_lpn_id,
lh1.dsp_locn as from_locn,
l.dsp_locn,
lh2.dsp_locn as dest_locn,
lp.inventory_lock_code
from wm_inventory W
left join Locn_hdr l
on w.location_id = L.locn_id
left join item_cbo i
on w.item_id = i.item_id
left join lpn_lock lp
on lp.tc_lpn_id = w.tc_lpn_id
left join task_dtl td
on td.cntr_nbr = w.tc_lpn_id
left join locn_hdr lh2
on td.dest_locn_id = lh2.locn_id
left join locn_hdr lh1
on td.PULL_LOCN_ID = lh1.locn_id
where i.color_desc = '00607'
and l.DSP_LOCN like '%SRT-0%'
and w.tc_lpn_id not like '%J%'
group by i.item_name, i.description, w.last_updated_source, w.tc_lpn_id, l.dsp_locn, lp.inventory_lock_code, lh1.dsp_locn, lh2.dsp_locn
order by w.last_updated_dttm asc;
To order by a column that's aggregated, you have to specify the aggregation:
order by MAX(w.last_updated_dttm) asc
Some implementations (including Oracle, you gave an Oracle error code) allow you to order by the aggregated column's alias:
order by MOST_RECENT_DTTM asc

How to create distinct count from queries with several tables

I am trying to create one single query that will give me a distinct count for both the ActivityID and the CommentID. My query in MS Access looks like this:
SELECT
tbl_Category.Category, Count(tbl_Activity.ActivityID) AS CountOfActivityID,
Count(tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;
I know the answer must somehow include SELECT DISTINCT but am not able to get it to work. Do I need to create multiple subqueries?
This is really painful in MS Access. I think the following does what you want to do:
SELECT ac.Category, ac.num_activities, aco.num_comments
FROM (SELECT ca.category, COUNT(*) as num_activities
FROM (SELECT DISTINCT c.Category, a.ActivityID
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as caa
GROUP BY ca.category
) as ca LEFT JOIN
(SELECT c.Category, COUNT(*) as num_comments
FROM (SELECT DISTINCT c.Category, co.CommentId
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as aco
GROUP BY c.Category
) as aco
ON aco.CommentId = ac.CommentId
Note that your LEFT JOINs are superfluous because the WHERE clause turns them into INNER JOINs. This adjusts the logic for that purpose. The filtering is also very tricky, because it uses both tables, requiring that both subqueries have both JOINs.
You can use DISTINCT:
SELECT
tbl_Category.Category, Count(DISTINCT tbl_Activity.ActivityID) AS CountOfActivityID,
Count(DISTINCT tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;

Access Subquery On mulitple conditions

This SQL query needs to be done in ACCESS.
I am trying to do a subquery on the total sales, but I want to link the sale to the province AND to product. The below query will work with one or the other: (po.product_name = allp.all_products) AND (p.province = allp.all_province); -- but it will no take both.
I will be including every month into this query, once I can figure out the subquery on with two criteria.
Select
p.province as [Province],
po.product_name as [Product],
all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id)
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province
)
as allp
on (po.product_name = allp.all_products) AND (p.province = allp.all_province);
Make the first select sql into a table by giving it an alias and join table 1 to table 2. I don't have your table structure or data to test it but I think this will lead you down the right path:
select table1.*, table2.*
from
(Select
p.province as [Province],
po.product_name as [Product]
--removed this ,all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id) table1
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province --check your group by, I dont think you want pp1.price here if you want to aggregate
) as table2 --changed from allp
on (table1.product = table2.all_products) AND (table1.province = table2.all_province);

ORA-01427: single-row subquery returns more than one row - I get this error even though I use SELECT DISTINCT

I am trying to make a query that selects all the drivers that were fined in the same place where another driver was fined.
SELECT DISTINCT(c.IdSofer), s.NumeSofer
FROM Soferi s
INNER JOIN contraventii c ON c.IdSofer= s.IdSofer
HAVING (SELECT DISTINCT IdLocContr FROM Contraventii c
INNER JOIN Soferi s ON c.IdSofer=s.IdSofer
INNER JOIN Localitati l ON s.IdLocSofer=l.IdLoc
WHERE s.NumeSofer='Maneta Gheorghe' AND l.DenLoc='Pocreaca' AND l.Jud='IS' GROUP BY IdLocContr) = c.IdLocContr
GROUP BY s.NumeSofer, c.IdLocContr, c.IdSofer;
This is what I tried but I get the error message
ORA-01427: single-row subquery returns more than one row.
If I run only only the SELECT statement between parentheses it works fine. It shows the id of cities (two cities) where this driver was fined. But if I try to run the code as I wrote here I get this error.
EDIT
This is the SQL from my comment...
SELECT DISTINCT(c.IdSofer)
,s.NumeSofer
FROM Soferi s INNER JOIN contraventii c
ON c.IdSofer= s.IdSofer
GROUP BY s.NumeSofer
,c.IdLocContr
,c.IdSofer
HAVING (SELECT DISTINCT IdLocContr
FROM Contraventii c INNER JOIN Soferi s
ON c.IdSofer=s.IdSofer INNER JOIN Localitati l
ON s.IdLocSofer=l.IdLoc
WHERE s.NumeSofer = 'Maneta Gheorghe'
AND l.DenLoc = 'Pocreaca'
AND l.Jud = 'IS'
GROUP BY IdLocContr) = c.IdLocContr
WHERE c.IdLocContr IN (
SELECT DISTINCT IdLocContr
FROM Contraventii c
INNER JOIN Soferi s ON c.IdSofer=s.IdSofer
INNER JOIN Localitati l ON s.IdLocSofer=l.IdLoc
WHERE s.NumeSofer = 'Maneta Gheorghe' AND l.DenLoc = 'Pocreaca' AND l.Jud = 'IS'
)
Just a few notes for your benefit.
The distinct isn't really necessary inside an in subquery although I left it there. Also you were using both distinct and group by which were redundant for that query. Having comes into play when you want to filter based on group aggregates.
It's too long to put in comment, so I put it here. Debugging is part of programmer's job. Have you checked whether the query below returns one row or not? If not, then that's what you have to fix.
SELECT DISTINCT IdLocContr
FROM Contraventii c
INNER JOIN Soferi s ON c.IdSofer=s.IdSofer
INNER JOIN Localitati l ON s.IdLocSofer=l.IdLoc
WHERE s.NumeSofer='Maneta Gheorghe' AND l.DenLoc='Pocreaca' AND l.Jud='IS'
GROUP BY IdLocContr
From the look at it, I doubt it will only return 1 row.
your having clause should return one value:
SELECT DISTINCT IdLocContr
FROM Contraventii c INNER JOIN Soferi s
ON c.IdSofer=s.IdSofer INNER JOIN Localitati l
ON s.IdLocSofer=l.IdLoc
WHERE s.NumeSofer = 'Maneta Gheorghe'
AND l.DenLoc = 'Pocreaca'
AND l.Jud = 'IS'
AND rownum<=1
GROUP BY IdLocContr

Trouble with aggregate in Where clause, Selecting Max(x) When Max(x) != 3

I am trying to reconfigure the below sql to only pull records when the Max(Field) != 3 but keep getting an error (detailed) below.
This is the code before adding the Where Max(field) != 3
SELECT P.Code,
MAX(PW.v1) AS V1
FROM SW
INNER JOIN S ON SW.S_Id = S.Id
INNER JOIN PW ON SW.PW_Id = PW.Id
INNER JOIN PON S.P_Id = P.id
WHERE S.P_Id = P.id
GROUP BY P.Code
My Attempt
SELECT P.Code,
MAX(PW.v1) AS V1
FROM SW
INNER JOIN S ON SW.S_Id = S.Id
INNER JOIN PW ON SW.PW_Id = PW.Id
INNER JOIN PON S.P_Id = P.id
WHERE S.P_Id = P.id
AND (SELECT MAX(PW.v1)
FROM SW AS SW2
WHERE SW.PWId = SW2.PW_Id) != 3
GROUP BY P.Code
This is the error I get and not sure what to do:
An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
Traditional method of filtering on results of an aggregate can be achieved by using HAVING clause. I also removed the unnecessary WHERE clause as you already joined those 2 tables on that column. Here is the query:
SELECT P.Code
,MAX(PW.v1) AS V1
FROM SW
INNER JOIN S
ON SW.S_Id = S.Id
INNER JOIN PW
ON SW.PW_Id = PW.Id
INNER JOIN P
ON S.P_Id = P.id
GROUP BY P.Code
HAVING MAX(PW.v1)!=3;