How to group by condition and average only if column value is not null in bigquery sql - google-bigquery

Hi I have a table that shows the category of product and another table with daily price of the product. I would like to get the average price of the category where average not count null values. How do I achieve this? Example of table product
product
category
apple
fruit
pear
fruit
grape
fruit
celery
vegetables
cabbage
vegetables
chicken
meat
turkey
meat
beef
meat
another table with daily price and productid as columns and the price in the rows
date
apple
pear
grape
celery
cabbage
chicken
turkey
beef
2022-01-01
2
4
1
2
3
4
3
2022-01-02
2
2
2
4
3
2022-01-03
2
2
2
3
into
date
fruit
vegetables
meat
2022-01-01
3
1.5
3.3
2022-01-02
2
2
3.5
2022-01-02
2
2
3
Where average is only to columns where it is not null, it would be better not to do it manually.

Consider below query using UNPIVOT AND PIVOT:
SELECT * FROM (
SELECT date, category, price
FROM prices UNPIVOT (price FOR productid IN (apple, pear, grape, celery, cabbage, chicken, turkey, beef)) p
JOIN category c ON c.product = p.productid
) PIVOT (AVG(price) FOR category IN ('fruit', 'vegetables', 'meat'))
ORDER BY date;

Consider also below approach
create temp function keys(input string) returns array<string> language js as """
return Object.keys(JSON.parse(input));
""";
create temp function values(input string) returns array<string> language js as """
return Object.values(JSON.parse(input));
""";
select *
from (
select date, category, round(avg(safe_cast(price as float64)), 2) avg_price
from prices t, unnest([struct(to_json_string(t) as json)]),
unnest(keys(json)) product with offset
join unnest(values(json)) price with offset using(offset)
left join products using(product)
where product != 'date'
group by date, category
)
pivot (any_value(avg_price) for category IN ('fruit', 'vegetables', 'meat'))
if applied to sample data in your question - output is
Potential benefit of using above is to eliminate need in enlisting all column names from products table, which are 8 in your example but in reality most likely much more! Obviously, another way to address this is to build dynamic query and run it using execute immediate which you can find quite a number of examples here on SO.
But, assuming that number of categories is significantly lower (just few as in your example) to compare with number of products - I would use this approach as execute immediate has its own drawbacks ...

Related

SQL query show customers who bought apples, but not potatoes

Not sure how to explain this..
I have a similar table, but i have simplified it with the following:
I have a table of goods shipped to different cusotmers. Some have bought apples only, others have bought apples and potates.
I want an SQL query to return only customers where "To be billed" = Yes AND the customer hasnt bought any vegetables.
So for example if the table looks like this:
Item
Name
Group
To_be_billed
CustomerNo.
2000
Apple
Fruit
Yes
1
2000
Apple
Fruit
No
2
2000
Apple
Fruit
No
3
2000
Apple
Fruit
Yes
4
2000
Apple
Fruit
Yes
5
4000
Potato
Vegetable
No
2
4000
Potato
Vegetable
No
4
I want the query to return:
Item
Name
Group
To_be_billed
CustomerNo.
2000
Apple
Fruit
Yes
1
2000
Apple
Fruit
Yes
5
The reason 4 has bought apples, and is to be billed, but the customer also bought Potatoes, so is to be ignored...
You can create a CTE to check for CustomerNo.s that you need to ignore, and then use not exists:
with bought_veg as
(
select "CustomerNo."
from tbl
where tbl."Group" like 'Vegetable'
)
select tbl.*
from tbl
where not exists (select 1 from bought_veg where tbl."CustomerNo." = bought_veg."CustomerNo.")
and tbl.To_be_billed = 'Yes'
Example without CTE:
select tbl.*
from tbl
where not exists (select "CustomerNo." from tbl t2 where tbl.[CustomerNo.] = t2.[CustomerNo.] and "Group" like 'Vegetable')
and tbl.To_be_billed = 'Yes'

How to merge two rows and sum the columns

product
quantity
price
milk
3
10
bread
7
3
bread
5
2
And my output table should be
product
total_price
milk
30
bread
31
I can't seem to get my code to work. Here is my code
SELECT product, (SELECT (quantity*unit_price)
FROM shopping_history AS sh ) AS total_price
FROM shopping_history
GROUP BY product
You are looking for the aggregate function SUM (which doesn't require a sub-query) e.g.
SELECT product, SUM(quantity*unit_price) AS Total_Price
FROM shopping_history
GROUP BY product

SQL: How to display items from one table according to categories from another table, and counting the total items in each category

I have two tables, a category table, and a items table. The category table have the following fields:
project_No
cat_ID
cat_Description
The items table has the following fields:
project_No
cat_ID
item_Id
item_description
item_Qty
item_cost
Now I need to write a query that displays all the items for each category, but I also want to count the amount of items in each category
Now the output must first list the category before the items in that catgegory and then list all the items in that category, and giving a total for the amount of items in that category, then another category and the items, for example
Beverages
Coffee $1.50 4
Tea $2.50 4
Total Items 2
Tin Food
Peas $0.50 10
Meatballs $1 20
total items 2
I need to write this SQL and place it inside my TADOQuery component in Delphi
Please can anyone assist me
Select category_table.Cat_Description, item_table.Item_Desctiption, SUM(Item_table.Item_Cost) as Total_Cost, SUM(item_Table.Item_Qty) as Total_Qty
From Items_table join Category_Table
on items_Table.Cat_Id = Category_Table.Cat_Id and items_Table.Project_no = Category_table.Project_no
This would get you the result:
Beverages Coffee $1.50 4
Beverages Tea $2.50 4
Tin Food Peas $0.50 10
Tin Food Meatballs $1.00 20
I summed your cost, but if you just want cost listed, remove the sum from the option.

In SQL, how find the total of a row over time?

A table and I want to know the total of my rows over time. For example. Here's my table:
Date Fruit Sold
Mon apple 4
Mon pear 5
Mon orange 2
Tues apple 3
Tues pear 2
Tues orange 1
The table I want back is:
Fruit Sold
apple 7
pear 7
orange 3
What is a query that I can do this? However, with my real situation, I have hundreds of types of fruit. So how do I query with out specifying each type of fruit each time?
That would be along the lines of:
select fruit, sum(sold) as sold
from fruitsales
group by fruit
-- adding something like <<where date = 'Mon'>> if you want to limit it.
This will aggregate the individual sold columns (by summing) for each fruit type.
here is how to do it:
select fruit, sum(sold)
from table
group by fruit
cheers...
Group by Time
select fruit, sum(sold),substring(saletime,1,3) from table group by fruit,substring(saletime,1,3)

SQL summary by ID with period to period comparison

I am a beginner in SQL, hope someone can help me on this:
I have a Items Category Table:
ItemID | ItemName | ItemCategory | Active/Inactive
100 Carrot Veg Yes
101 Apple Fruit Yes
102 Beef Meat No
103 Pineapple Fruit Yes
And I have a sales table:
Date | ItemID | Sales
01/01/2010 100 50
05/01/2010 101 200
06/01/2010 101 250
06/01/2010 102 300
07/01/2010 103 50
08/01/2010 100 100
10/01/2010 102 250
How Can I achieve a sales summary table by Item By Period as below (with only active item)
ItemID | ItemName | ItemCategory | (01/01/2010 – 07/01/2010) | (08/01/2010 – 14/01/1020)
100 Carrot Veg 50 100
101 Apple Fruit 450 0
103 Pineapple Fruit 0 0
A very dirty solution
SELECT s.ItemId,
(SELECT ItemName FROM Items WHERE ItemId = s.ItemId) ItemName,
ISNULL((SELECT Sum(Sales)FROM sales
WHERE [Date] BETWEEN '2010/01/01' AND '2010/01/07'
AND itemid = s.itemid
GROUP BY ItemId),0) as firstdaterange,
ISNULL((SELECT Sum(Sales)FROM sales
WHERE [Date] BETWEEN '2010/01/08' AND '2010/01/14'
AND itemid = s.itemid
GROUP BY ItemId), 0) seconddaterange
FROM Sales s
INNER JOIN Items i ON s.ItemId = i.ItemId
WHERE i.IsActive = 'Yes'
GROUP BY s.ItemId
Again a dirty solution, also the dates are hardcoded. You can probably turn this into a stored procedure taking in the dates as parameters.
I'm not too clued up on PIVOT command but maybe that will be worth a google.
You can pivot the data using the SQL PIVOT operator. Unfortunately, that operator has limited scope due to the requirement to pre-specify the output columns.
You normally achieve this by grouping on a calculated column (in this case, one that computes the week number or first day of the week in which each row falls). You can then either generate SQL on-the-fly with columns derived using SELECT DISTINCT week FROM result, or just drop the result into Excel and use its pivot table facility.