SQL not a GROUP BY expression with OracleSQL and InnerQuery Error - sql

I have little problem with my SQL query.
I want to get my CUSTOMERS table id, name, surname, and all money they spent on my shop i've created.
SELECT o.CUSTOMER_ID AS "ID", c.name AS "Name", c.SURNAME AS "Surname",
(SELECT op.AMOUNT * p.PRICE
FROM PRODUCTS p
WHERE p.id = op.PRODUCT_ID) AS "Money spent"
FROM ORDERS o
LEFT JOIN CUSTOMERS c ON c.ID = o.CUSTOMER_ID
LEFT JOIN ORDERS_PRODUCTS op ON op.ORDER_ID = o.id
GROUP BY o.CUSTOMER_ID;
And i have error message like this:
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action:
Error at Line: 1 Column: 31
I have to say, that i have to use GroupBy clause, because i have this in my school project requirements.
And this is my base diagram, if it could help you.
http://i61.tinypic.com/2d1okut.jpg

As you can see in the ORACLE docs
SelectItems in the SelectExpression with a GROUP BY clause must contain only aggregates or grouping columns.
This means that if you only group by o.CUSTOMER_ID, all the other fields in the select list must be aggregate functions (like COUNT, MAX, etc.).
In the case of fields that repeat values in each group (as name and surname) you should include them in the GORUP BY clause.
To include the sum of money spent, you could add another LEFT JOIN with PRODUCTS and select SUM(op.amount*p.price) without a subquery.
That would be
SELECT o.CUSTOMER_ID AS "ID", c.name AS "Name", c.SURNAME AS "Surname",
SUM(op.AMOUNT*p.PRICE) AS "Money spent"
FROM ORDERS o
LEFT JOIN CUSTOMERS c ON c.ID = o.CUSTOMER_ID
LEFT JOIN ORDERS_PRODUCTS op ON op.ORDER_ID = o.id
LEFT JOIN PRODUCTS p ON p.id = op.PRODUCT_ID
GROUP BY o.CUSTOMER_ID, c.name AS "Name", c.SURNAME
ORDER BY o.CUSTOMER_ID, c.name AS "Name", c.SURNAME;
Remember always to define the sort order of your queries, otherwise it will be undefined.

Related

JOINS AND SUBQUERY

Question -
Display customer Id, name, and total number of orders, for orders handled by salesman Marshall, but only if customer name begins on General or ends on Electric. Exclude customers who placed a single order, but include customers without orders as well. Sort the result based on the total number of orders descending and then by name ascending.
Do not use LIKE operator and do not join 3 tables.
Questions output
Current Query
SELECT c.customer_id,
c.name,
Count(o.order_id) "# of Orders"
FROM customers c
left join orders o
ON c.customer_id = o.customer_id
WHERE Substr(c.name, 1, 7) = 'General'
OR Substr(c.name, -8) = 'Electric'
AND o.order_id IN (SELECT o.order_id
FROM orders o,
order_items oi
WHERE o.order_id = oi.order_id
AND o.salesman_id = (SELECT employee_id
FROM employees
WHERE
last_name = 'Marshall')
GROUP BY o.order_id
HAVING Count(customer_id) > 1)
GROUP BY c.customer_id,
c.name;
Database -
Not sure what I am doing wrong here.
That's a really contrived assignment... Here is one option:
select c.customer_id, c.customer_name, count(o.orderid) cnt
from customers c
left join orders o
on o.customer_id = c.customer_id
and (select last_name from employee e where e.employee_id = o.salesman_id) = 'Marshall'
where substr(c.name, 1, 7) = 'General' or substr(c.name, -8) = 'Electric'
group by c.customer_id, c.customer_name
having count(o.orderid) <> 1
The base idea is a left join. The where clause filters on the customer name - without like: you had that already.
To filter on the salesman name without an additional join, we use a correlated subquery in the on clause of the left join. There is no need to bring order_items, nor to select again from orders here.
Finally, the filtering on the order counts goes to the having clause.

SQL column name is keyword "category"

This query works:
SELECT product_name, unit_price, order_due_date
FROM orders
FULL OUTER JOIN products ON orders.product_id = products.product_id
WHERE product_name = 'bun';
whereas this one throws an error:
ORA-00936: "missing expression"
SELECT product_name, unit_price, order_due_date
FROM orders
FULL OUTER JOIN products ON orders.product_id = products.product_id
WHERE [category] = 'soft drink';
I can't figure what's wrong with the second
When you have multiple tables in a query, you should always qualify column names. In your first query, the WHERE clause is undoing the FULL JOIN. In fact, I am guessing that an INNER JOIN is most appropriate. How would an order have a product not in the products table?
SELECT p.product_name, ?.unit_price, o.order_due_date
FROM orders o INNER JOIN
products p
ON o.product_id = p.product_id
WHERE p.product_name = 'bun';
As for your second query, [ and ] are not delimiters in Oracle. Either leave them out:
WHERE category = 'soft drink'
Or, if for some obscure reason the column name actually has those characters, then use double quotes:
WHERE "[category]" = 'soft drink';

Add a Sum Function within Select Statement

I'm trying to add a sum function to my sql statement. Currently I'm using Oracle 12G;
my select statement is as follows
select Distinct o.id as ID, o.orderno as "order", a.itemno as "Item Number",
od.total_qty_ord/a.pallet_ptsper as "Total Pallets" From Orders o, ord_detail od,
arinvt a
where o.id = od.orders_id (+) and a.id (+) = od.arinvt_id and o.orderno = '1323-PASO'
order by ID
Currently when I run this I get two different records if my sales order has two different line items. I want to be able to sum the "Total Pallets" section of my script. Is this possible?
Must the selected o.id also entered in de group by clause? I think so.
select Distinct o.id as ID,
o.orderno as "order",
a.itemno as "Item Number",
sum(od.total_qty_ord/a.pallet_ptsper) as "Total Pallets"
From Orders o,
ord_detail od,
arinvt a
where o.id = od.orders_id (+)
and a.id (+) = od.arinvt_id
and o.orderno = '1323-PASO'
group by o.order, a.itemno, o.id ---> include the o.id
order by ID

Need hints on seemingly simple SQL query

I'm trying to do something like:
SELECT c.id, c.name, COUNT(orders.id)
FROM customers c
JOIN orders o ON o.customerId = c.id
However, SQL will not allow the COUNT function. The error given at execution is that c.Id is not valid in the select list because it isn't in the group by clause or isn't aggregated.
I think I know the problem, COUNT just counts all the rows in the orders table. How can I make a count for each customer?
EDIT
Full query, but it's in dutch... This is what I tried:
select k.ID,
Naam,
Voornaam,
Adres,
Postcode,
Gemeente,
Land,
Emailadres,
Telefoonnummer,
count(*) over (partition by k.id) as 'Aantal bestellingen',
Kredietbedrag,
Gebruikersnaam,
k.LeverAdres,
k.LeverPostnummer,
k.LeverGemeente,
k.LeverLand
from klanten k
join bestellingen on bestellingen.klantId = k.id
No errors but no results either..
When using an aggregate function like that, you need to group by any columns that aren't aggregates:
SELECT c.id, c.name, COUNT(orders.id)
FROM customers c
JOIN orders o ON o.customerId = c.id
GROUP BY c.id, c.name
If you really want to be able to select all of the columns in Customers without specifying the names (please read this blog post in full for reasons to avoid this, and easy workarounds), then you can do this lazy shorthand instead:
;WITH o AS
(
SELECT CustomerID, CustomerCount = COUNT(*)
FROM dbo.Orders GROUP BY CustomerID
)
SELECT c.*, o.OrderCount
FROM dbo.Customers AS c
INNER JOIN dbo.Orders AS o
ON c.id = o.CustomerID;
EDIT for your real query
SELECT
k.ID,
k.Naam,
k.Voornaam,
k.Adres,
k.Postcode,
k.Gemeente,
k.Land,
k.Emailadres,
k.Telefoonnummer,
[Aantal bestellingen] = o.klantCount,
k.Kredietbedrag,
k.Gebruikersnaam,
k.LeverAdres,
k.LeverPostnummer,
k.LeverGemeente,
k.LeverLand
FROM klanten AS k
INNER JOIN
(
SELECT klantId, klanCount = COUNT(*)
FROM dbo.bestellingen
GROUP BY klantId
) AS o
ON k.id = o.klantId;
I think this solution is much cleaner than grouping by all of the columns. Grouping on the orders table first and then joining once to each customer row is likely to be much more efficient than joining first and then grouping.
The following will count the orders per customer without the need to group the overall query by customer.id. But this also means that for customers with more than one order, that count will repeated for each order.
SELECT c.id, c.name, COUNT(orders.id) over (partition by c.id)
FROM customers c
JOIN orders ON o.customerId = c.id

ORA-00979: not a GROUP BY expression? [duplicate]

This question already has answers here:
Oracle ORA-00979 - "not a GROUP BY expression"
(4 answers)
Closed 8 years ago.
I have found the solution to this, but what in case one of the column is a subquery, how can i include it in group by, or do i need to include that in group by. I will paste the query here..
SELECT s.customerid, s.denomid,
(SELECT su.quantity
FROM stockupdations su
WHERE s.customerid = su.custid
AND s.denomid = su.denomid
AND s.curid = su.curid) AS cur_stock, c.name AS cus_name, d.denomname AS denom,
cur.curcode AS currency
FROM stock s
LEFT JOIN customers c
ON s.customerid = c.custid
LEFT JOIN denomination d
ON d.denomid = s.denomid
LEFT JOIN currency cur
ON cur.curid = s.curid
GROUP BY s.denomid, s.customerid, c.name, d.denomname, cur.curcode
ORDER BY s.customerid ASC
What about a WITH statement?
WITH tmp AS
(
SELECT s.customerid, s.denomid,
c.name AS cus_name,
d.denomname AS denom,
cur.curcode AS currency
FROM stock s
LEFT JOIN customers c
ON s.customerid = c.custid
LEFT JOIN denomination d
ON d.denomid = s.denomid
LEFT JOIN currency cur
ON cur.curid = s.curid
GROUP BY s.denomid, s.customerid, c.name, d.denomname, cur.curcode
ORDER BY s.customerid ASC
)
SELECT tmp.customerid, tmp.denomid,
su.quantity,
tmp.cus_name,
tmp.denom,
tmp.currency
FROM tmp
INNER JOIN stockupdations su
ON tmp.customerid = su.custid
AND tmp.denomid = su.denomid
AND tmp.curid = su.curid
You can use your "Inner query" in the from clause than on the select.
Say I have a CUSTOMER table and ORDER table,
I can have something like
SELECT C.CUSTOMER_ID, COUNT(T.ORDER_ID)
FROM CUSTOMERS C
JOIN (SELECT CUSTOMER_ID, ORDER_ID, ORDER_DATE, ORDER_STATUS FROM ORDERS O WHERE O.STATUS <> 'DECLINED') T
ON T.CUSTOMER_ID = C.CUSTOMER ID
GROUP BY C.CUSTOMER_ID
(This SQL is just an example, and I know there are better ways to write this, but I could not think of any other example immediately)
You don't have to do everything at once. Try breaking your query into multiple pieces. Subqueries, analytic functions, or other complicated logic will look like simple rows to the outer query. (Don't worry about performance, Oracle will re-write it and do everything as one step if it makes sense.)
--Step 3
select [simple values]
from
(
--Step 2
select [insanity]
from
(
--Step 1
select [madness]
from
[impossible joins]
)
)
group by [simple values]