Why does an incorrect syntax error near appears? - sql

I get an error that Incorrect syntax near the keyword 'DESC'.
SELECT S.NAME, SUM([QTY] * [PRICE]) AS SALES
FROM Invoices$ Inv INNER JOIN InvDetails$ InvD ON
Inv.INVOICE_ID=InvD.INVOICE_ID
INNER JOIN Products$ P ON InvD.PRODUCT_ID=P.PRODUCT_ID
INNER JOIN Stores$ S ON S.STORE_ID=Inv.STORE_ID
GROUP BY SALES DESC
The expected result is to print all stores and their sales sorted by total sales(SALES) in desecding order

You mean to GROUP BY S.NAME, not SALES.
Also GROUP BY does not care about order, so move DESC to after the ORDER BY. You can't combine GROUP BY and ORDER BY into a single clause.
GROUP BY S.NAME
ORDER BY SALES DESC;

You query should look like this:
SELECT S.NAME, SUM([QTY] * [PRICE]) AS SALES
FROM Invoices$ Inv INNER JOIN
InvDetails$ InvD
ON Inv.INVOICE_ID = InvD.INVOICE_ID INNER JOIN
Products$ P
ON InvD.PRODUCT_ID = P.PRODUCT_ID INNER JOIN
Stores$ S
ON S.STORE_ID = Inv.STORE_ID
GROUP BY S.NAME
ORDER BY SALES DESC;
DESC is supported as a keyword for GROUP BY in MySQL (although I think that usage has been deprecated in v8). However, that is an extension not used by other databases.
In any case, the GROUP BY should contain all the non-aggregated keys in the SELECT. That would be S.NAME, not SALES.

you need to name column add in group by
SELECT S.NAME, SUM([QTY] * [PRICE]) AS SALES
FROM Invoices$ Inv INNER JOIN InvDetails$ InvD ON
Inv.INVOICE_ID=InvD.INVOICE_ID
INNER JOIN Products$ P ON InvD.PRODUCT_ID=P.PRODUCT_ID
INNER JOIN Stores$ S ON S.STORE_ID=Inv.STORE_ID
GROUP BY S.NAME order by SALES desc

Related

Find the nth highest

SELECT CONCAT(C.CUSTOMER_FNAME, ' ',C.CUSTOMER_LNAME) AS FullNAME, SUM(QTY* PRICE)AS TOTAL_SPENDINGS
FROM (SELECT DISTINCT TOP 2 TOTAL_SPENDINGS) RESULT
Customers$ C INNER JOIN Invoices$ Inv ON C.CUSTOMER_ID=Inv.CUSTOMER_ID
INNER JOIN InvDetails$ InvD ON Inv.INVOICE_ID=InvD.INVOICE_ID
INNER JOIN Products$ P ON P.PRODUCT_ID=InvD.PRODUCT_ID
GROUP BY C.CUSTOMER_FNAME,C.CUSTOMER_LNAME
ORDER BY TOTAL_SPENDINGS DESC
I am trying to prin the k-highest spending customers this is what i have done until now but i get
Incorrect syntax near 'Customers$'.
You are missing the join condition between the calculated table RESULT and the Customers table:
SELECT CONCAT(C.CUSTOMER_FNAME, ' ',C.CUSTOMER_LNAME) AS FullNAME, SUM(QTY* PRICE)AS TOTAL_SPENDINGS
FROM (SELECT DISTINCT TOP 2 TOTAL_SPENDINGS) RESULT
<missing INNER / LEFT join here>
Customers$ C <missing ON here> INNER JOIN Invoices$ Inv ON C.CUSTOMER_ID=Inv.CUSTOMER_ID
INNER JOIN InvDetails$ InvD ON Inv.INVOICE_ID=InvD.INVOICE_ID
INNER JOIN Products$ P ON P.PRODUCT_ID=InvD.PRODUCT_ID
GROUP BY C.CUSTOMER_FNAME,C.CUSTOMER_LNAME
ORDER BY TOTAL_SPENDINGS DESC

What is 'keyword' is missing from this query?

This is what I have;
SELECT c.customerFN, c.customerEmail, p.productName,
SUM(p.unitsonstock + p.unitsordered) AS "All Units"
FROM customer c
INNER JOIN order o
WHERE c.customerID=o.customerID
INNER JOIN orderDetails d
WHERE o.orderID=d.orderID
INNER JOIN product p
WHERE p.productCode=l.productCode
WHERE orderDate <= '2015-03-15'
ORDER BY productName;
When I enter this the database throws a "missing keyword" error at the fourth line. Could you tell me what it is that I'm missing
Instead of WHERE in line 5, 7 and 9 you need to use ON. You are also using function SUM, but there is no GROUP BY. Change your query like this:
SELECT c.customerFN, c.customerEmail, p.productName,
SUM(p.unitsonstock + p.unitsordered) AS "All Units"
FROM customer c
INNER JOIN order o
ON c.customerID=o.customerID
INNER JOIN orderDetails d
ON o.orderID=d.orderID
INNER JOIN product p
ON p.productCode=l.productCode
WHERE orderDate <= '2015-03-15'
GROUP BY c.customerFN, c.customerEmail, p.productName
ORDER BY p.productName;
JOIN is performed using the ON clause, not with a WHERE:
...
FROM customer c
INNER JOIN order o ON c.customerID=o.customerID
INNER JOIN orderDetails d ON o.orderID=d.orderID
INNER JOIN product p ON p.productCode=d.productCode
WHERE orderDate <= '2015-03-15'
...
The WHERE clause that comes after join should be used like you have it in your query.
Apart from the problem with the JOIN there is also a problem using SUM without grouping. You probably want something like:
SELECT c.customerFN, c.customerEmail, p.productName,
SUM(p.unitsinstock + p.unitsordered) AS "All Units"
FROM customer c
INNER JOIN order o ON c.customerID=o.customerID
INNER JOIN orderDetails d ON o.orderID=d.orderID
INNER JOIN product p ON p.productCode=d.productCode
WHERE orderDate <= '2015-03-15'
GROUP BY customerFN, customerEmail, productName
ORDER BY p.productName;
Use of SUM function implies a GROUP BY clause. Every column selected that is not part of an aggregate function like SUM must be present in the GROUP BY clause.

SQL join/sum assistance, need to combine the 2 queries inside

Here's a fiddle:
http://sqlfiddle.com/#!2/7f479a/2
What I am trying to achieve is the Inventory from this query:
SELECT
di.distributors_inventory_stock,
op.op_products_id,
p.products_mfr_part_number,
op.op_products_name,
p.products_brand,
op.op_products_qty,
SUM(op.op_products_qty) AS TotalSold
FROM orders_products op
JOIN orders o
ON op.op_order_id = o.orders_id
JOIN products p
ON p.products_id = op.op_products_id
JOIN distributors_inventory di
ON di.distributors_inventory_product_ID = op.op_products_id
WHERE o.orders_distributor_id = '90'
AND o.orders_date_purchased BETWEEN '2014-06-01 00:00:00' AND '2014-08-01 23:59:59'
GROUP BY op.op_products_id
ORDER BY TotalSold DESC
With the TotalSold and product list from this query:
SELECT
op.op_products_id,
p.products_mfr_part_number,
op.op_products_name,
p.products_brand,
SUM(op.op_products_qty) AS TotalSold
FROM orders_products op
JOIN orders o ON op.op_order_id = o.orders_id
JOIN products p ON p.products_id = op.op_products_id
WHERE o.orders_distributor_id = '90'
AND o.orders_date_purchased BETWEEN '2014-06-01 00:00:00' AND '2014-08-01 23:59:59'
GROUP BY op.op_products_id
ORDER BY TotalSold DESC
Because the distributors data is driving the list of products, that needs to be the first table queried, then left join to the other tables, putting all conditions on the other tables in the join condition:
SELECT
di.distributors_inventory_stock stock,
di.distributors_inventory_product_ID product_id,
p.products_mfr_part_number mfr_part_number,
op.op_products_name order_product_name,
p.products_brand brand,
p.products_supplier_name supplier_name,
SUM(op.op_products_qty) / count(o.orders_id) AS TotalSold
FROM distributors_inventory di
LEFT JOIN orders_products op ON di.distributors_inventory_product_ID = op.op_products_id
LEFT JOIN orders o ON op.op_order_id= o.orders_id
AND o.orders_date_purchased BETWEEN '2014-06-01 00:00:00' AND '2014-08-01 23:59:59'
LEFT JOIN products p ON p.products_id = di.distributors_inventory_product_ID
WHERE di.distributors_inventory_distributor_ID = '90'
GROUP BY 1, 2, 3, 4, 5, 6
ORDER BY TotalSold DESC
See SQLFiddle
The key points here are:
select first from the table that controls what rows are returned
left join to the sales tables
move the conditions on left joined tables, specifically the date range, from the where clause into the join condition
removed column that was both summed and selected (makes no sense)
corrected group by clause problem (you must list all non-aggregated selected columns for the grouping to work as you expect)
join to product table directly from distributors table so product info is available for products without sales in the period
give columns friendlier names
added supplier product name (because we can)
modified sum() due to account for multiple joined rows from the order table (from comment)
Of all the tips, the third is the most critical. Because left joined rows have nulls in their columns, putting a condition on them in the where clause will result in only rows that actually join being returned - effectively making the joins inner joins. Conditions in the join condition still restrict rows returned, while allowing the join to be an outer join
Your First Query is Good ... just add LEFT OUTER JOIN To distributors_inventory table.. and you should get your expected result set.
Modified Query: (check the comment in below query for modification)
SELECT di.distributors_inventory_stock, op.op_products_id, p.products_mfr_part_number, op.op_products_name, p.products_brand, op.op_products_qty, SUM(op.op_products_qty) AS TotalSold
FROM orders_products op
JOIN orders o ON op.op_order_id = o.orders_id
JOIN products p ON p.products_id = op.op_products_id
-- Comment: Modification in below Line, inner join changed to left outer join)
LEFT OUTER JOIN distributors_inventory di ON di.distributors_inventory_product_ID = op.op_products_id
WHERE o.orders_distributor_id = '90'
AND o.orders_date_purchased BETWEEN '2014-06-01 00:00:00' AND '2014-08-01 23:59:59'
GROUP BY op.op_products_id
ORDER BY TotalSold DESC
You will get null values under distributors_inventory_stock column if corresponding row is not found in this table.. if you want zero instead of null then change it as below in select clause
Select di.distributors_inventory_stock
To
Select ifnull(di.distributors_inventory_stock,0) AS distributors_inventory_stock

How to have SQL INNER JOIN accept null results

I have the following query:
SELECT TOP 25 CLIENT_ID_MD5, COUNT(CLIENT_ID_MD5) TOTAL
FROM dbo.amazonlogs
GROUP BY CLIENT_ID_MD5
ORDER BY COUNT(*) DESC;
Which returns:
283fe255cbc25c804eb0c05f84ee5d52 864458
879100cf8aa8b993a8c53f0137a3a176 126122
06c181de7f35ee039fec84579e82883d 88719
69ffb6c6fd5f52de0d5535ce56286671 68863
703441aa63c0ac1f39fe9e4a4cc8239a 47434
3fd023e7b2047e78c6742e2fc5b66fce 45350
a8b72ca65ba2440e8e4028a832ec2160 39524
...
I want to retrieve the corresponding client name (FIRM) using the returned MD5 from this query, so a row might look like:
879100cf8aa8b993a8c53f0137a3a176 126122 Burger King
So I made this query:
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL, c.FIRM
FROM dbo.amazonlogs a
INNER JOIN dbo.customers c
ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY a.CLIENT_ID_MD5, c.FIRM
ORDER BY COUNT(*) DESC;
This returns something like:
879100cf8aa8b993a8c53f0137a3a176 126122 Burger King
06c181de7f35ee039fec84579e82883d 88719 McDonalds
703441aa63c0ac1f39fe9e4a4cc8239a 47434 Wendy's
3fd023e7b2047e78c6742e2fc5b66fce 45350 Tim Horton's
Which works, except I need to return an empty value for c.FIRM if there is no corresponding FIRM for a given MD5. For example:
879100cf8aa8b993a8c53f0137a3a176 126122 Burger King
06c181de7f35ee039fec84579e82883d 88719 McDonalds
69ffb6c6fd5f52de0d5535ce56286671 68863
703441aa63c0ac1f39fe9e4a4cc8239a 47434 Wendy's
3fd023e7b2047e78c6742e2fc5b66fce 45350 Tim Horton's
How should I modify the query to still return a row even if there is no corresponding c.FIRM?
Replace INNER JOIN with LEFT JOIN
use LEFT JOIN instead of INNER JOIN
Instead of doing an INNER join, you should do a LEFT OUTER join:
SELECT
a.CLIENT_ID_MD5,
COUNT(a.CLIENT_ID_MD5) TOTAL,
ISNULL(c.FIRM,'')
FROM
dbo.amazonlogs a LEFT OUTER JOIN
dbo.customers c ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY
a.CLIENT_ID_MD5,
c.FIRM
ORDER BY COUNT(0) DESC
http://www.w3schools.com/sql/sql_join.asp
An inner join excludes NULLs; you want a LEFT OUTER join.
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL, IsNull(c.FIRM, 'Unknown') as Firm
FROM dbo.amazonlogs a
LEFT JOIN dbo.customers c ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY a.CLIENT_ID_MD5, c.FIRM ORDER BY COUNT(*) DESC;
This will give you a value of "Unknown" when records in the customers table don't exist. You could obviously drop that part and just return c.FIRM if you want to have actual nulls instead.
Change your INNER JOIN to an OUTER JOIN...
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL, c.FIRM
FROM dbo.amazonlogs a
LEFT OUTER JOIN dbo.customers c
ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
GROUP BY a.CLIENT_ID_MD5, c.FIRM
ORDER BY COUNT(*) DESC;
WITH amazonlogs_Tallies
AS
(
SELECT a.CLIENT_ID_MD5, COUNT(a.CLIENT_ID_MD5) TOTAL
FROM dbo.amazonlogs a
GROUP
BY a.CLIENT_ID_MD5
),
amazonlogs_Tallies_Firms
AS
(
SELECT a.CLIENT_ID_MD5, a.TOTAL, c.FIRM
FROM amazonlogs_Tallies a
INNER JOIN dbo.customers c
ON c.CLIENT_ID_MD5 = a.CLIENT_ID_MD5
)
SELECT CLIENT_ID_MD5, TOTAL, FIRM
FROM amazonlogs_Tallies_Firms
UNION
SELECT CLIENT_ID_MD5, TOTAL, '{{NOT_KNOWN}}'
FROM amazonlogs_Tallies
EXCEPT
SELECT CLIENT_ID_MD5, TOTAL, '{{NOT_KNOWN}}'
FROM amazonlogs_Tallies_Firms;

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]