How to add a column with data based on another column - sql

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

Related

Different results in SQL based on what columns I display

I am trying to run a query to gather the total items on hand in our database. However it seems i'm getting incorrect data. I am selecting selecting just the amount field and summing it using joins from separate tables based on certain parameters, however if I display additional fields such as order number, and date all of a sudden im getting different data, even though those fields are being used as filters in the query. Is it because its not in the select statement? If it needs to be in the select statement is it possible to not display them?
Here are the two queries.
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt'
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
providing a sum of 21667457.20
and with the added columns
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt', [Requested Delivery Date], sh.No_, tw.[Status]
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
group by sh.[Requested Delivery Date], sh.No_, tw.[Status]
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
order by sh.[Requested Delivery Date] ASC
Providing a sum of 12319998
I'm self taught in SQL so I may be misunderstanding something obvious, thanks for the help.
With no sample data, I am going to have to demonstrate this in principle. In the latter query you have a GROUP BY meaning the scope of the values in the HAVING will differ, and thus the filtering from said HAVING will be different.
Let's take the following sample data:
CREATE TABLE dbo.MyTable (Grp char(1),
Quantity int,
Required int);
INSERT INTO dbo.MyTable (Grp, Quantity, [Required])
VALUES('a',2,7),
('a',14,2),
('b',4, 7),
('b',3,4),
('c',17,5);
Now we'll perform an overly simplified version of your query:
SELECT SUM(Quantity)
FROM dbo.MyTable
HAVING SUM(Quantity) > SUM(Required);
This brings back the value 40; which is the SUM of all the values in Quantity. A value is returned because the total SUM of Required is 25.
Now let's add a GROUP BY like your second query:
SELECT SUM(Quantity)
FROM dbo.MyTable
GROUP BY Grp
HAVING SUM(Quantity) > SUM(Required);
Now we have 2 rows, with the values 16 and 17 giving a total value of 33. That's because the rows where Grp have a value of 'B' are filtered out, as the SUM of Quantity is lower that Required for 'B'.
The same is happening in your data; in the grouped data you have groups where the HAVING condition isn't met, so those rows aren't returned.

How to group this query with repeated values on one column and the other column containing no repeated data?

I'm practicing SQL and I'm trying to do a query of the best seller by section in a shop, I have this query so far:
select idrama, nombre, apellido, max(valortotal)
from(
select personarama.idrama, persona.nombre, persona.apellido,sum(detalle.cantidad*precio.valor) as valortotal
from persona,factura,precio,detalle, personarama
where persona.idpersona=factura.idvendedor
and personarama.idpersona=persona.idpersona
and factura.numfactura=detalle.numfactura
and precio.referencia=detalle.referencia
and factura.fecha between precio.fechaini and precio.fechafin
group by persona.idpersona, personarama.idrama, persona.nombre, persona.apellido
order by 4 DESC
) as vendedorRama
group by idrama, nombre, apellido;
when I execute the query I get the sellers by section and the amount of money they have sold.
And I need to get the best seller by section, and the only way to do this, is grouping by only idrama, but with this solution I cannot get the name and firstname of the seller. How could I group this data without losing those columns?
You can use window function like this:
select DISTINCT idrama, nombre, apellido, max(valortotal) OVER (PARTITION BY idrama) AS 'Max_of_valortotal'
from(
select personarama.idrama, persona.nombre, persona.apellido,sum(detalle.cantidad*precio.valor) as valortotal
from persona,factura,precio,detalle, personarama
where persona.idpersona=factura.idvendedor
and personarama.idpersona=persona.idpersona
and factura.numfactura=detalle.numfactura
and precio.referencia=detalle.referencia
and factura.fecha between precio.fechaini and precio.fechafin
group by persona.idpersona, personarama.idrama, persona.nombre, persona.apellido
order by 4 DESC
) as vendedorRama

SQL query with grouping

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;

Oracle SQL Developer 0913 - too many values

I'm trying to return the MINIMUM VALUE and the MAXIMUM VALUE in my PRICE table(the field is the val_price).
What is the problem with this query?
select des_price, val_price from price
WHERE val_price IN
(SELECT MIN(val_price), MAX(val_price) from price);
The error message is:
00913. 00000 - "too many values"*Cause:
*Action:
If I try with just one value in the inner select everything works fine, but with multiple values I don't know why is not working.
This example works fine with 2 values in the follow inner select:
UPDATE price SET val_price = val_price * 1.05
WHERE des_price in('NORMAL','RELEASE');
You cannot select two columns from sub-query when you are using only one column in Where clause
Try this way
SELECT des_price,
val_price
FROM price
WHERE val_price IN (SELECT Min(val_price)
FROM price
UNION ALL
SELECT Max(val_price)
FROM price);
or
SELECT des_price,
val_price
FROM price
WHERE ( val_price, val_price ) IN (SELECT Min(val_price),
Max(val_price)
FROM price)

SQL: Using UNION

Here is the question and database info.
Use the UNION command to prepare a full statement for customer 'C001' - it should be laid out as follows. (Note that the values shown below are not correct.) You may be able to use '' or NULL for blank values - if necessary use 0.
Here is a link to the webpage with the database info. http://sqlzoo.net/5_0.htm or see the image below.
Here is what I have tried:
SELECT sdate AS LineDate, "delivery" AS LEGEND, price*quantity AS Total,"" AS Amount
FROM shipped
JOIN product ON (shipped.product=product.id)
WHERE badguy='C001'
UNION
SELECT rdate,notes, "",receipt.amount
FROM receipt
WHERE badguy='C001'
Here is what I get back:
Wrong Answer. The correct answer has 5 row(s).
The amounts don't seem right in the amount column and I can't figure out how to order the data by the date since it is using two different date columns (sdate and rdate which are UNIONED).
Looks like the data in the example is being aggregated by date and charge type using group by, that's why you are getting too many rows.
Also, you can sort by the alias of the column (LineDate) and the order by clause will apply to all the rows in the union.
SELECT sdate AS LineDate, "delivery" AS LEGEND, SUM(price*quantity) AS Total,"" AS Amount
FROM shipped
JOIN product ON (shipped.product=product.id)
WHERE badguy='C001'
GROUP BY sdate
UNION
SELECT rdate, notes, "",receipt.amount
FROM receipt
WHERE badguy='C001'
ORDER BY LineDate
It's usually easiest to develop each part of the union separately. Pay attention to the use of "null" to separate the monetary columns. The first select gets to name the columns.
select s.sdate as tr_date, 'Delivery' as type, sum((s.quantity * p.price)) as extended_price, null as amount
from shipped s
inner join product p on p.id = s.product
where badguy = 'C001'
group by s.sdate
union all
select rdate, notes, null, sum(amount)
from receipt
where badguy = 'C001'
group by rdate, notes
order by tr_date