SQL query with grouping - sql

I have a problem by solving following task:
'Show for every seller how much he earned (quantity * product_price) by selling the product PS4 in the year 2013'
The relations are:
seller(id , seller_name, advertised_by);
product( id, product_name, product_price);
sale(id, seller_id, product_id, quantity, date);
I inserted following data:
INSERT into seller VALUES
(1,'Bob',NULL),
(2,'Mary',1),
(3,'Peter',1),
(4,'Parker',1),
(5,'Jeff',1);
INSERT INTO product VALUES
(1,'PS4',100),
(2,'XBOX One',300),
(3,'Laptop',500);
INSERT INTO sale VALUES
(1,1,1,1,'4 5 2013'),
(2,2,1,2,'5 6 2013'),
(3,3,1,3,'6 6 2013'),
(4,4,1,4,'6 6 2013');
I know not using foreign keys or using varchar for date isn't good but I want to have the example being simple.
SELECT seller.id,seller.seller_name, (sale.quantity * product.price) AS sale
FROM seller,product,sale
WHERE product.id = sale.product_id
AND product.product_name = 'PS4'
AND sale.date like '%2013'
GROUP by seller.id;
I know that I have to use a GROUP BY but grouping by seller.id doesn't work.

You need to group by every column that isn't aggregated, and apply an aggregate function to the others. Here, you need to add sellar_name to the group by clause (which shouldn't change the grouping, as the id is already unique), and sum the sales.
Also, as a side note, using implicit joins (having more than one table in the from clause) has been deprecated for several years, and it's recommended you use an explicit join instead:
SELECT seller.id,seller.seller_name, SUM(sale.quantity * product.price) AS sale
FROM seller
JOIN sale ON sale.seller_id = seller.id
JOIN product ON product.id = sale.product_id
WHERE product.product_name = 'PS4' AND sale.date like '%2013'
GROUP BY seller.id;

Related

How to add a column with data based on another column

I have a BQ table that looks look this:
and I want to add a column that divides the shipping_handling based on the number of rows under the same invoice, in this case since there are 5 entries under invoice J513183, it will be 461.71/5 = 92.34
which would look like this:
tried adding this code "shipping_handling/count(invoice) as shipping" but it's not working. I hope anyone can help me find a solution on this google big query sql
Below is for BigQuery Standard SQL
#standardSQL
SELECT *,
ROUND(shipping_handling / (COUNT(*) OVER(PARTITION BY invoice)), 2) AS shipping
FROM `project.dataset.table`
You can use a window function:
select invoice_date,
invoice,
description,
shipping_handling,
avg_line_total,
shipping_handling / count(*) partition by (invoice) as shipping
from the_table;
Depending on your DBMS, you might need to cast one of the values in the division to a numeric data type otherwise it might use integer division which does not yield decimal digits.
One possible solution would be to create temp table with count of groups and than use it in your query
-- DROP TABLE IF EXISTS
IF OBJECT_ID(N'tempdb..#tmpInvoice') IS NOT NULL
BEGIN
DROP TABLE #tmpInvoice
END
-- GROUP INVOICES AND INSERT INTO TEMP TABLE
SELECT invoice as invoiceId, COUNT(invoice) invoiceCount
INTO #tmpInvoice
FROM BQ GROUP BY invoice
-- GET SHIPPING WITH ADDITIONAL SELECT
SELECT invoice_date,
invoice,
description,
shipping_handling,
avg_line_total,
cast((shipping_handling/(SELECT invoiceCount from #tmpInvoice where invoiceId = invoice)) as numeric(10,2)) Shipping
FROM BQ
-- GET SHIPPING WITH INNER JOIN
SELECT bq.invoice_date,
bq.invoice,
bq.description,
bq.shipping_handling,
bq.avg_line_total,
cast((bq.shipping_handling/ti.invoiceCount) as numeric(10,2)) Shipping
FROM BQ bq
INNER JOIN #tmpInvoice ti on bq.invoice = ti.invoiceId

SQL Pivot column values

I have tried following this and this(SQL Server specific solution) but were not helpful.
I have two tables, Product and Sale and I want to find how many products are sold on each day. But I want to pivot the table so that columns become the products name and each row will contain the amount of products sold for each day ordered by the day.
Simplified schema is as following
CREATE TABLE product (
id integer,
name varchar(40),
price float(2)
);
CREATE TABLE sale(
id integer,
product_id integer,
transaction_time timestamp
);
This is what I want
I only managed to aggregate the total sales per day per product but I am not able to pivot the product names.
select date(sale.transaction_date)
, product.id
, product.name
, count(product_id)
from sale inner join
product on sale.product_id = product.id
group by date(sale.transaction_date)
, product.id
, product.name
This is the situation so far
Please suggest.
You need pivoting logic, e.g.
select
s.transaction_date::date,
count(case when p.name = 'intelligent_rubber_clock' then 1 end) as intelligent_rubber_clock,
count(case when p.name = 'intelligent_iron_wallet' then 1 end) as intelligent_iron_wallet,
count(case when p.name = 'practical_marble_car' then 1 end) as practical_marble_car
from sale s
inner join product p
on s.product_id = p.id
group by
s.transaction_date::date;
Since your expected output aggregates by date alone, then only the transaction date should be in your GROUP BY clause. The trick used here is to take the count of a CASE expression which returns 1 when the record is from a given product, and 0 otherwise. This generates conditional counts for each product, all in separate columns. To add more columns, just add more conditional counts.

Get Sum of quantities from multiple tables?

I have at least 8 tables from where I need to match the customer name and fetch the quantities and get the sum of all the quantities fetched from these 8 tables. I am trying to write a code which will ignore the customer whose sum of quantities is zero.
For an example lets take two tables purchase_sugar and sales_sugar I have tried a lot of queries but only this one is returning some result which is wrong.
SELECT sum(purchase_sugar.qty + sales_sugar.qty) AS Total_Amount from purchase_sugar inner join sales_sugar on purchase_sugar.supplier = sales_sugar.customer WHERE purchase_sugar.supplier = "+str(x.id)+"
The Table structures are like:
purchase_sugar have two columns supplier and qty.
And sales_sugar have structure like customer and qty.
How can I get the SUM of QUANTITIES of these tables if I provide one name and search it through these tables and get the quantities. The other thing is that I dont want the customer to be found in all the tables. If it is found in one table we should just get the quantity from that one table and for that reason I don't think that JOIN is useful or may be i am wrong.
To take care of the situation where a supplier/customer is not in all the tables, you can use union all and group by:
select name, sum(p_qty) as sum_p, sum(s_qty) as sum_s,
sum(p_qty) + sum(s_qty)
from ((select ps.supplier as name, ps.qty as p_qty, 0 as s_qty
from purchase_sugar ps
) union all
(select ss.customer as name, 0, ss.qty
from sales_sugar ss
)
) s
group by name;
Notes:
This query gets results for all names. You can use a where clause to restrict the results to one name.
You don't have to split the quantities into two (or eight) different columns, if you just want the overall sum.
You can aggregate before the union all, but that is not necessary.
you should JOIN the sum and not sum the join
select t1.purchase_sum + sales_sum as Total_Amount
from (
select purchase_sugar.supplier, sum(purchase_sugar.qty) as purchase_sum
from purchase_sugar
group by purchase_sugar.supplier
) t1
inner join (
select sales_sugar.customer, sum(sales_sugar.qty) as sales_sum
from sales_sugar
group by sales_sugar.customer
) t2 on t1.supplier = t2.customer and t1.supplier = "+str(x.id)+"

Dynamic column in Oracle SQL select

I have three tables:
T_ORDER_PLACEMENTS (ORDER_ID, CUSTOMER_ID, ORDER_DATE)
T_ORDER_DETAILS (ORDER_ID, STOCK_ID)
T_STOCK_DETAILS(STOCK_ID, STOCK_NAME, STOCK_PRICE)
Can someone please help me to write a query which generates the following output:
STOCK_ID, STOCK_NAME, STOCK_PRICE, ORDERED_STATUS
1 stock1 5000 ordered
2 stock2 10000 unordered
Populate the ORDERED_STATUS column with 'ordered' if the stock is ordered and 'unordered' if the stock is unordered.
SELECT
t_stock_details.*,
CASE WHEN order_check.stock_id IS NULL THEN 'unordered' ELSE 'ordered' END AS ordered_status
FROM
t_stock_details
LEFT JOIN
(
SELECT stock_id FROM t_order_details GROUP BY stock_id
)
order_check
ON order_check.stock_id = t_stock_details.stock_id
The sub-query checks to see which stock_ids have an order associated with them. It also uses GROUP BY to ensure only one row is returned per stock_id, no matter how many orders are found.
The LEFT JOIN ensures that every row in t_stock_details is returned, whether or not it is successfully joined to anything. Where there is a successful join, we know there has been an order. It will also only ever be joined on to one row at the most (thanks to the above mentioned GROUP BY, so no duplication is being caused).
An unsuccessful join will have NULL in the order_check.stock_id, so we use that to check which string to return, using a CASE statement.

SQL select query with two tables

I'm struggling with a task. I need to create a select query which:
For each specific listed date shows date and revenue where revenue is number of sold units multiplied with unit price (but ONLY if revenue is greater than or equal to 10 000).
There are two tables: product & order.
Product contains columns: unittype, price. And order contains columns: unittype, date, number (number of units sold)
This is my try on the select query:
SELECT
order.date,
product.price*order.number AS revenue
FROM product
INNER JOIN
order
ON product.unittype = order.unittype
WHERE product.price*order.number >= 10000;
None of my results are even close to 10k (between 39 and 1.3k) so I'm wondering if I've typed it wrong or if there are any more efficient ways to type it?
If this is meant to be for the total for the day (and not the individual line), you need an aggregate and a having clause:
SELECT
order.date,
SUM(product.price*order.number) AS revenue
FROM product
INNER JOIN
order
ON product.unittype = order.unittype
GROUP BY order.date
HAVING SUM(product.price*order.number) >= 10000