I'm a beginner in SQL using Google BigQuery, and I wrote a syntax to find the best seller by 'price' and 'category' with some kind of 'status'. here's the syntax:
SELECT
oi.product_id
, p.category as product_category
, DATE_TRUNC(oi.created_at, MONTH) AS month_order
, oi.status as status_order
, ROUND(SUM(oi.sale_price)) as subtotal_price
FROM
`bigquery-public-data.thelook_ecommerce.order_items` oi
LEFT JOIN
`sql-project-376612.thelook_ecommerce.products` p
ON
oi.product_id=p.id
WHERE DATE(oi.created_at) BETWEEN '2022-12-01' AND '2022-12-31'
AND oi.status = 'Shipped'
AND p.category IS NOT NULL
GROUP BY p.category
ORDER BY 5 DESC
please help me to find why Group By function didnt work? Thanks in advance, mate.
I've found the answer using excel because using sql can't :(
You need to GROUP BY the columns that you use in WHERE:
SELECT
oi.product_id
, p.category as product_category
, DATE_TRUNC(oi.created_at, MONTH) AS month_order
, oi.status as status_order
, ROUND(SUM(oi.sale_price)) as subtotal_price
FROM
`bigquery-public-data.thelook_ecommerce.order_items` oi
LEFT JOIN
`sql-project-376612.thelook_ecommerce.products` p
ON
oi.product_id=p.id
WHERE DATE(oi.created_at) BETWEEN '2022-12-01' AND '2022-12-31'
AND oi.status = 'Shipped'
AND p.category IS NOT NULL
GROUP BY oi.product_id
, p.category
, DATE_TRUNC(oi.created_at, MONTH)
, oi.status
ORDER BY 5 DESC
Related
I have written the below SQL query to join four tables and do the calculations based on criteria but throws an error. Will appreciate for any help. Thanks
Not sure where I am doing wrong or whether my logic is not right?
SELECT C.cust_name,
R.Reg_name,
sum(CASE WHEN P.Class = 'R' THEN T.Amount*.1 WHEN P.Class = 'P' THEN T.Amount*.2 ELSE T.Amount*.1 END) AS Calc_Amount
FROM Customers C,
Regions R,
transactions T,
customer_class P
WHERE C.reg_id = R.reg_id, C.cust_id = T.cust_id, C.cust_id = P.cust_id
AND P.class_id, P.class IN (SELECT max(class_id), class
FROM customer_class
GROUP BY cust_id)
AND T.Time, T.Amount IN (SELECT max(time),
Amount
FROM transactions
GROUP BY cust_id)
GROUP BY C.cust_name
ORDER BY C.cust_name
SQL command not properly ended
You can't combine multiple conditions with an , in the WHERE clause. You probably want an and there:
WHERE C.reg_id = R.reg_id
AND C.cust_id = T.cust_id
AND C.cust_id = P.cust_id
But I strongly recommend to switch to an explicit JOIN in the FROM clause:
FROM Customers C
JOIN Regions R ON C.reg_id = R.reg_id
JOIN transactions T ON C.cust_id = T.cust_id
JOIN customer_class P ON C.cust_id = P.cust_id
Additionally, when you want to use multiple columns with an IN operator, you need to enclose the columns on the left hand side with parentheses, e.g. (P.class_id, P.class) instead of P.class_id, P.class.
You also need to include all columns that are not used in an aggregation in the group by clause.
So the complete query should look something like:
SELECT C.cust_name,
R.Reg_name,
sum(CASE WHEN P.Class = 'R' THEN T.Amount*.1 WHEN P.Class = 'P' THEN T.Amount*.2 ELSE T.Amount*.1 END) AS Calc_Amount
FROM Customers C
JOIN Regions R ON C.reg_id = R.reg_id
JOIN transactions T ON C.cust_id = T.cust_id
JOIN customer_class P ON C.cust_id = P.cust_id
WHERE (P.class_id, P.class) IN (SELECT max(class_id), class
FROM customer_class
GROUP BY cust_id)
AND (T.Time, T.Amount) IN (SELECT max(time), Amount
FROM transactions
GROUP BY cust_id)
GROUP BY C.cust_name, R.Reg_name
ORDER BY C.cust_name
I would recommend proper join syntax and using window functions. I think you want something like this:
SELECT C.cust_name,
sum(CASE WHEN P.Class = 'R' THEN T.Amount*.1 WHEN P.Class = 'P' THEN T.Amount*.2 ELSE T.Amount*.1 END) AS Calc_Amount
FROM Customers C JOIN
Regions R
C.reg_id = R.reg_id JOIN
(SELECT T.*,
ROW_NUMBER() OVER (PARTITION BY T.cust_id ORDER BY T.Time DESC) as seqnum
FROM transactions T
) T
ON C.cust_id = T.cust_id AND seqnum = 1 JOIN
(SELECT P.*,
ROW_NUMBER() OVER (PARTITION BY P.cust_id ORDER BY P.class_id DESC) as seqnum
FROM customer_class P
) P
ON C.cust_id = P.cust_id
GROUP BY C.cust_name
ORDER BY C.cust_name;
However, I'm not sure that this logic does anything useful. You should probably ask a new question with sample data and desired results.
Building on #a_horse_with_no_name's answer - the problem is with the GROUP BY expressions in the subqueries in the WHERE clause. It looks like you should be using
SELECT C.cust_name,
R.Reg_name,
sum(CASE WHEN P.Class = 'R' THEN T.Amount*.1 WHEN P.Class = 'P' THEN T.Amount*.2 ELSE T.Amount*.1 END) AS Calc_Amount
FROM Customers C
JOIN Regions R ON C.reg_id = R.reg_id
JOIN transactions T ON C.cust_id = T.cust_id
JOIN customer_class P ON C.cust_id = P.cust_id
WHERE (P.class_id, P.class) IN (SELECT max(class_id), class
FROM customer_class
GROUP BY class)
AND (T.Time, T.Amount) IN (SELECT max(time), Amount
FROM transactions
GROUP BY amount)
GROUP BY C.cust_name, R.Reg_name
ORDER BY C.cust_name
That will probably execute, but I'm not sure it'll give you the results you wanted. Another possibility is
SELECT C.cust_name,
R.Reg_name,
sum(CASE WHEN P.Class = 'R' THEN T.Amount*.1 WHEN P.Class = 'P' THEN T.Amount*.2 ELSE T.Amount*.1 END) AS Calc_Amount
FROM Customers C
JOIN Regions R ON C.reg_id = R.reg_id
JOIN transactions T ON C.cust_id = T.cust_id
JOIN customer_class P ON C.cust_id = P.cust_id
WHERE (P.class_id, P.class) IN (SELECT max(class_id), class
FROM customer_class
GROUP BY class)
AND (T.cust_id, T.Time, T.Amount) IN (SELECT cust_id, max(time), max(Amount)
FROM transactions
GROUP BY cust_id)
GROUP BY C.cust_name, R.Reg_name
ORDER BY C.cust_name
but I doubt the second sub-select does what you had in mind. But without test data and expected results it's impossible to understand what you're trying to do. You might consider editing the question and adding test data and expected results as text, not as an image so people can test their queries against the expected results.
I have this SQL in SQL Server:
SELECT
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data,
SUM(ValorUnitario) AS Total,
SUM(Quantidade) AS Quantidade
FROM
Itens
INNER JOIN
Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN
Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE
Cabecalho.Data >= '2016-01-01'
AND Cabecalho.Data <= '2018-12-31'
GROUP BY
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data
ORDER BY
4 DESC
It is returning the following result.
The highlighted values are repeating, I do not want to be repeated, I want to show only once each item and that the Quantidade and Total fields are SUM.
For example:
`Camisa Polo` -> **Quantidade = 23**
`Calça Jeans` -> **Quantidade = 15**
`Camiseta Estampada` -> **Quantidade = 21**
Assuming thate the relation between Sales and SaleItems is based on SalesId
you can use between assign to your_start_date and your_end_date a proper value
select Products.ProductName
, sum(SaleItems.Price)
, sum(SaleItems.Quantity)
from Products
inner join SaleItems on SaleItems.IdProduct = Products.IdProduct
inner join Sales on Sales.IdSale = SaleItems.IdSale
where SaleDate between your_start_date and your_end_date
group by Products.ProductName
In you case remove or aggregated the Cabecalho.Data column eg:
SELECT Itens.Mercadoria
, Mercadoria.Nome
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC
or
SELECT Itens.Mercadoria
, Mercadoria.Nome
, max(Cabecalho.Data)
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC
i am running following query
select
to_char(sale_order.date_order ,'DD-MM-YYYY') , sum(sale_order.amount_total) as amount
from
public.sale_order
where
sale_order.order_year = '2015' and
sale_order.order_month = 'April'
group by
to_char(sale_order.date_order ,'DD-MM-YYYY') order by to_char(sale_order.date_order ,'DD-MM-YYYY') asc
its giving correct output
to_char.. amount
"14-04-2015"; 1298.00
"15-04-2015"; 4294.00
"16-04-2015"; 1398.00
"17-04-2015"; 1927.00
"18-04-2015"; 3094.00
"19-04-2015"; 6988.00
"20-04-2015"; 6641.00
"21-04-2015"; 3045.00
but i am trying to enter a condition which have multiple table connection then it gives different amount value
select
to_char(sale_order.date_order ,'DD-MM-YYYY') , sum(sale_order.amount_total) as amount
from
public.sale_order ,
public.sale_order_line ,
public.product_product ,
public.product_template ,
public.product_category
where
sale_order_line.product_id = product_product.id AND
product_product.product_tmpl_id = product_template.id AND
product_template.categ_id = product_category.id AND
sale_order.id = sale_order_line.order_id AND
sale_order_line.product_id = product_product.id AND
product_product.product_tmpl_id = product_template.id AND
product_template.categ_id = product_category.id AND
product_category.name = 'Starchi' and
sale_order.order_year = '2015' and
sale_order.order_month = 'April'
group by to_char(sale_order.date_order ,'DD-MM-YYYY') order by to_char(sale_order.date_order ,'DD-MM-YYYY') asc
then it gives different output
to_char amount
"14-04-2015"; 1298.00
"15-04-2015"; 4294.00
"16-04-2015"; 1398.00
"17-04-2015"; 2805.00 //wrong output
"18-04-2015"; 6188.00 //wrong output
"19-04-2015"; 13976.00 //wrong output
"20-04-2015"; 19229.00 //wrong output
"21-04-2015"; 3045.00
what is the exact problem please anybody can tell ?
and how to solve it ?
You made a mistake in your WHERE clauses, as Gordon Linoff already commented, leading to duplicate rows being retrieved and then summed up to give wrong totals. Following wildplasser's advice in his comment, using the JOIN syntax is much cleaner and less error-prone. Your query would look like this:
SELECT to_char(o.date_order, 'DD-MM-YYYY') AS "date", sum(o.amount_total) AS amount
FROM public.sale_order o
JOIN public.sale_order_line l ON l.order_id = o.id
JOIN public.product_product pp ON pp.id = l.product_id
JOIN public.product_template pt ON pt.id = pp.product_tmpl_id
JOIN public.product_category pc ON pc.id = pt.categ_id
WHERE pc.name = 'Starchi'
AND o.order_year = '2015'
AND o.order_month = 'April'
GROUP BY o.date_order
ORDER BY o.date_order ASC
[USING #Patrick 's cleaned up code] Most probable cause is that an 1:N relation exists between orders and order_lines, causing the orders with multiple order_lines to be included in the sum() more than once.
SELECT to_char(o.date_order, 'DD-MM-YYYY') AS date_order
, sum(o.amount_total) AS amount
FROM public.sale_order o
WHERE EXISTS ( SELECT *
-- These tables probably have an N:1 relation
-- to public.sale_order
-- We don't have to sum them; just check existence.
FROM public.sale_order_line l
JOIN public.product_product pp ON pp.id = l.product_id
JOIN public.product_template pt ON pt.id = pp.product_tmpl_id
JOIN public.product_category pc ON pc.id = pt.categ_id
WHERE pc.name = 'Starchi'
AND l.order_id = o.id
)
AND o.order_year = '2015'
AND o.order_month = 'April'
GROUP BY o.date_order
ORDER BY o.date_order ASC
;
Im stuck atm. Trying to figure out how to use an aggregate function like SUM(column1*column2) for making results in multiple columns. I want to print ex. SUM(qty*unitprice) where orderdate between "blabla" and "blabla",
and then i want another column which uses the same function(sum(qty*unitprice)
but with additional expressions in the where clause. this is my code example, it doesnt show anything:
select Orderdates, Sales, SalesDisc
FROM ( select month(OH.OrderDate) as Orderdates, sum(OD.OrderQty*OD.UnitPrice) as Sales
from sales.SalesOrderDetail OD
inner join sales.salesorderheader OH on
OD.SalesOrderID = OH.SalesOrderID
where OrderDate >= ('2014-01-01') and OrderDate < ('2015-01-01')
group by month(OH.orderdate)
) A
Join
(select month(OH.OrderDate) as orderdatez, sum(OD.OrderQty*OD.UnitPrice) as SalesDisc
from sales.SalesOrderDetail OD
inner join sales.SalesOrderHeader OH on
OD.SalesOrderID = OH.SalesOrderID
where OrderDate >= ('2014-01-01') and OrderDate < ('2015-01-01')
and OD.SpecialOfferID between 2 and 16
Group by Month(OH.orderdate)
) B
on A.Orderdates = B.orderdatez and A.Sales = B.SalesDisc
If am not wrong this is what you need
SELECT Month(OH.OrderDate) AS Orderdates,
Sum(OD.OrderQty * OD.UnitPrice) AS Sales,
Sum(CASE
WHEN OD.SpecialOfferID BETWEEN 2 AND 16 THEN ( OD.OrderQty * OD.UnitPrice )
ELSE 0
END) AS SalesDisc
FROM sales.SalesOrderDetail OD
INNER JOIN sales.salesorderheader OH
ON OD.SalesOrderID = OH.SalesOrderID
WHERE OrderDate >= ( '2014-01-01' )
AND OrderDate < ( '2015-01-01' )
GROUP BY Month(OH.orderdate)
Note : It will be more meaningful if you add year(OH.orderdate) in group by
The exact error I am getting is: "Unknown column 'trans_paid' in 'where clause'"
My query ($from_date and $to_date are correctly formatted):
SELECT
o.order_id,
o.order_po_no,
o.order_ship_date,
acct.acct_company,
SUM( ROUND( i.item_qty * i.item_price, 2 ) ) AS item_amount, (
SELECT SUM( trans_amount )
FROM transactions
WHERE order_id = o.order_id
AND trans_pending =0
AND trans_date >= '$from_date'
AND trans_date <= '$to_date'
) AS trans_paid
FROM orders AS o
INNER JOIN accounts AS acct ON o.acct_id = acct.acct_id
INNER JOIN items AS i ON o.order_id = i.order_id
WHERE (o.order_status =7 or o.order_status = 4)
AND trans_paid IS NOT NULL
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id
You can't reference aliased columns in the SELECT cause from the WHERE clause. You'll have to wrap it in a subquery if you want to filter on it.
Standard SQL doesn't allow you to refer to aggregate columns in the WHERE clause. You need to move the trans_paid condition to a HAVING clause to make it work.
Change
WHERE (o.order_status =7 or o.order_status = 4)
AND trans_paid IS NOT NULL
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id
to
WHERE (o.order_status =7 or o.order_status = 4)
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id
HAVING trans_paid IS NOT NULL
An alias name to be used in the Where clause has to be declared in the FROM clause...You simply renamed a column not actually rename an object such as a table.
use this query:
SELECT
o.order_id,
o.order_po_no,
o.order_ship_date,
acct.acct_company,
SUM( ROUND( i.item_qty * i.item_price, 2 ) ) AS item_amount,
trans_paid
FROM orders AS o
LEFT JOIN
(SELECT SUM( trans_amount ) AS trans_paid
FROM
WHERE trans_pending =0
AND trans_date >= '$from_date'
AND trans_date <= '$to_date'
) temp
USING order_id
INNER JOIN accounts AS acct ON o.acct_id = acct.acct_id
INNER JOIN items AS i ON o.order_id = i.order_id
WHERE (o.order_status =7 or o.order_status = 4)
AND trans_paid IS NOT NULL
AND acct.is_wholesale =1
AND acct.acct_company LIKE '%".$_POST['company']."%'
GROUP BY o.order_id