How can I sum a row's value in my table based on a specific type? - sql

My table looks like this. Its a table with an inventory of clothes.
Basically, an user can enter a type of clothe and a quantity.
When he did it, it add a new value in the table with the date of the input.
The type 2 is for shoes and the type 3 for shirts
What I'm trying to do is to sum the quantity based on the type like this :
So I tried this :
SELECT name, type, sum(quantity)
from Clothes
where type="2"
group by name
But it didn't work, it sums all the type of clothes. How can I do ?

Use case expressions to do conditional aggregation:
SELECT name,
SUM(case when type = 3 then quantity else 0 end) shirts,
SUM(case when type = 2 then quantity else 0 end) shoes
from Clothes
group by name

You should group using the type too.
Doing this you'll get a table with 3 columns:
1st one with the name, secondo col with the type and the third with the quantity
SELECT name, type, sum(quantity)
from Clothes
group by name,type
Then you should format as you wish the data
If otherwise you want to get the exact result with a query you should dig more deep and maybe using some 'Case' inside the sum function and put a zero if is not of the selected type:
select name,
sum(case when type = 3 then quantity else 0 end) as Shirts,
sum(case when type = 2 then quantity else 0 end) as Shoes
from Clothes
group by name;
result:

A solution using a PIVOT table will achieve the same result with multi-column aggregation of quantities corresponding to the type column:
SELECT [ProductName], [2] As Shoes, [3] As Clothes
FROM
(SELECT [ProductName], [ProductType], [Quantity] FROM [Inventory_Table])
AS DataSource
PIVOT
(SUM([Quantity]) FOR [ProductType] IN ([2], [3])) AS pvt_table
Note: For the above to work in SQL Server T-SQL I had to replace the [Name] and [Type] columns with other columns names.

Related

SQL Server : percentage calculation with new records as output

I have the below table as an output of a SQL query
ID Car Type Units Sold
---------------------------
1 Sedan 250
2 SUV 125
3 Total 375
I want a SQL query / procedure to produce below output
ID Car Type Units Sold
--------------------------
1 Sedan 250
2 SUV 125
3 Total 375
4 Sedan_Pct 66.67 (250/375)
5 SUV_Pct 33.33 (125/375)
Please note that Car Type will be increased in future and I want the percentage of each car type which should be appended to current table as '_Pct'.
Typically we might expect to see the percentages as a separate column, not as separate rows. That being said, we can generate the output you want using grouping sets in SQL Server:
WITH cte AS (
SELECT ID, CarType, SUM (UnitsSold) AS UnitsSold
FROM yourTable
GROUP BY
GROUPING SETS((ID, CarType), (CarType), ())
)
SELECT
ID,
COALECSE(CarType, 'Total') AS CarType,
CASE WHEN ID IS NOT NULL OR CarType IS NULL
THEN UnitsSold
ELSE 100.0 * UnitsSold /
SUM(CASE WHEN ID IS NOT NULL THEN UnitsSold END) OVER () END AS PctUnitsSold
FROM cte
ORDER BY
ID DESC,
CASE WHEN CarType IS NULL THEN 0 ELSE 0 END,
CarType;
Demo
A simpler solution will be using Union
SELECT CarType, UnitSold FROM Car
UNION
SELECT 'Total' CarType, SUM(UnitSold) UnitSold FROM Car
UNION
SELECT CarType + '_Pct' AS CarType, UnitSold / (SELECT SUM(UnitSold) FROM Car) * 100 AS UnitSold FROM Car
Might not be ideal in the long run
query for mysql server
use union all in view or stored procedure -
declare #totalunitsold numeric(15,0);
set #totalunitsold = (select unitsold from car where cartype='total')
select cartype,unitsold from car
union all
select cartype + '_pct', (unitsold/#totalunitsold) as pct from car
this may help you
SELECT CarType+'_Pct', UnitSold/TotalSale*100
FROM Car cross join (select sum(UnitSold) TotalSale from Car) X
you can union that with your Table
Don't do it! Just add an additional column, not new rows:
select t.*,
t.units_sold * 100.0 / sum(case when t.car_type = 'Total' then units_sold end) over () as ratio
from (<your query here>) t;
One fundamental reason why you want a different column is because ratio has a different type from units_sold. Everything in a column (even in a result set) should be a similar attribute.

SQL - Query the same column but with 2 different conditions

I have a table called Products which contains the entire catalog. That table has a unique Product_ID, the Category it belongs to, and then a field Available which shows in which countries (US, UK, DE, ...) the product can be sold. If a product can be sold on multiple then the combination Product_ID and Available looks like:
23523 DE
23523 UK
23523 US
...
I need to do a query that produces 3 columns:
Category Total_Number_Products DE_Number_Products
I can do this on 2 separate queries, one for Total_Number_Products and the other for DE_Number_Products, each one with a Count - the 1st one without any condition and the 2nd one checking if "Available = 'DE'".
How can I or should I query that same column with COUNT(Product_ID) twice on the same query, once for all the products and then for the DE specific products?
Please consider this:
select category,
count(*) total_number_products,
sum(case available when 'DE' then 1 else 0 end) de_number_products
from products
group by category
you can do conditional aggregation here:
select category,
count(*) as total_number_products,
count(case when country = 'DE' then 1 end) as DE_number_products
from your_table
group by category;

Pivot for redshift database

I know this question has been asked before but any of the answers were not able to help me to meet my desired requirements. So asking the question in new thread
In redshift how can use pivot the data into a form of one row per each unique dimension set, e.g.:
id Name Category count
8660 Iced Chocolate Coffees 105
8660 Iced Chocolate Milkshakes 10
8662 Old Monk Beer 29
8663 Burger Snacks 18
to
id Name Cofees Milkshakes Beer Snacks
8660 Iced Chocolate 105 10 0 0
8662 Old Monk 0 0 29 0
8663 Burger 0 0 0 18
The category listed above gets keep on changing.
Redshift does not support the pivot operator and a case expression would not be of much help (if not please suggest how to do it)
How can I achieve this result in redshift?
(The above is just an example, we would have 1000+ categories and these categories keep's on changing)
i don't think there is a easy way to do that in Redshift,
also you say you have more then 1000 categories and the number is growing
you need to taking in to account you have limit of 1600 columns per table,
see attached link
[http://docs.aws.amazon.com/redshift/latest/dg/r_CREATE_TABLE_usage.html][1]
you can use case but then you need to create case for each category
select id,
name,
sum(case when Category='Coffees' then count end) as Cofees,
sum(case when Category='Milkshakes' then count end) as Milkshakes,
sum(case when Category='Beer' then count end) as Beer,
sum(case when Category='Snacks' then count end) as Snacks
from my_table
group by 1,2
other option you have is to upload the table for example to R and then you can use cast function for example.
cast(data, name~ category)
and then upload the data back to S3 or Redshift
We do a lot of pivoting at Ro - we built python based tool for autogenerating pivot queries. This tool allows for the same basic options as what you'd find in excel, including specifying aggregation functions as well as whether you want overall aggregates.
Redshift released a Pivot/Unpivot functionality on last re:Invent 2021 (December 2021): https://docs.aws.amazon.com/redshift/latest/dg/r_FROM_clause-pivot-unpivot-examples.html
SELECT *
FROM (SELECT id, Name, Category, count FROM my_table) PIVOT (
SUM(count) FOR Category IN ('Coffees', 'Milkshakes', 'Beer', 'Snacks')
);
If you will typically want to query specific subsets of the categories from the pivot table, a workaround based on the approach linked in the comments might work.
You can populate your "pivot_table" from the original like so:
insert into pivot_table (id, Name, json_cats) (
select id, Name,
'{' || listagg(quote_ident(Category) || ':' || count, ',')
within group (order by Category) || '}' as json_cats
from to_pivot
group by id, Name
)
And access specific categories this way:
select id, Name,
nvl(json_extract_path_text(json_cats, 'Snacks')::int, 0) Snacks,
nvl(json_extract_path_text(json_cats, 'Beer')::int, 0) Beer
from pivot_table
Using varchar(max) for the JSON column type will give 65535 bytes which should be room for a couple thousand categories.
#user3600910 is right with the approach however 'END' is required else '500310' invalid operation would occur.
select id,
name,
sum(case when Category='Coffees' then count END) as Cofees,
sum(case when Category='Milkshakes' then count END) as Milkshakes,
sum(case when Category='Beer' then count END) as Beer,
sum(case when Category='Snacks' then count END) as Snacks
from my_table
group by 1,2
The answer given above worked for me after switching count to 1
select id,
name,
sum(case when Category='Coffees' then 1 end) as Cofees,
sum(case when Category='Milkshakes' then 1 end) as Milkshakes,
sum(case when Category='Beer' then 1 end) as Beer,
sum(case when Category='Snacks' then 1 end) as Snacks
from my_table
group by 1,2

How can I combine 3 queries into one query and the result form look like schedule table?

I have 3 select queries :
the result of first for heading of my table.(like : select id, name from cars)
the second result show left side of my schedule table shows the date of sales (select date from dates inner join car on date.carid = car.carid where date.date1 > XXX/XX/XX for example)
the third result returns the data for inside the table. and it is the price of each car in each date.
But I don't know how to combine them?
I guess you need something like this Working SQL Server fiddle here
You need either of the following
Pivot feature of SQL Server
Aggregate function with group-by
Query: Pivot feature of SQL Server
SELECT *
FROM
(
SELECT [SALE_DATE], [CAR_NAME], [COST]
FROM CARS_SALES
) AS source
PIVOT
(
MAX(COST)
FOR [CAR_NAME] IN ([BENZ] , [BMW], [RENAULT])
) as pvt;
Query: Aggregate function with group-by
SELECT SALE_DATE,
MAX(CASE WHEN CAR_NAME = 'BENZ' THEN COST ELSE NULL END) [BENZ],
MAX(CASE WHEN CAR_NAME = 'BMW' THEN COST ELSE NULL END) [BMW],
MAX(CASE WHEN CAR_NAME = 'RENAULT' THEN COST ELSE NULL END) [RENAULT]
FROM CARS_SALES
GROUP BY SALE_DATE
Both the Queries give an
output result
as below:
SALE_DATE BENZ BMW RENAULT
09/07/2014 (null) (null) 900
09/08/2014 100 200 300
09/09/2014 400 600 (null)
09/10/2014 700 500 800
It's really unclear, but based on that you've posted, the solution would be something like this:
select cars.name, dates.date, dates.price
from dates
left join cars on (cars.carid=dates.carid)
order by cars.name, dates.date;
This gets the car's name, price and the date in one query. But I don't understand what your third query is for. If you provide more information I'll update this answer.

sql query that will get a distinct type, brand, and model, but get a count of how many duplicates were found

I have a table "Competitor" and here are some of its columns:
Type | Brand | Model | Date | Resolution | etc.
The table will have duplicate Model entries (with obviously same Brand as well, but possibly a different Type (two possible types: 'ProAV' and 'Disti')). I need to build a query that will output a table like this:
Top (ProAV) | Top (Disti) | Last Occurrence | Brand | Model | Resolution | etc.
Basically I need a query that will get a distinct type, brand, and model, but get a count of how many duplicates were found and put that number in either Top (ProAV) or Top (Disti), whichever Type it has. I would need to pull the most recent (given Date) out of the duplicates, so that I can put its Date as the Last Occurrence field. I hope this makes sense, let me know if it doesn't.
SELECT SUM(CASE WHEN Type = 'ProAV' THEN 1 ELSE 0 END) AS TopProAV,
SUM(CASE WHEN Type = 'Disti' THEN 1 ELSE 0 END) AS TopDisti,
MAX(Date) AS LastOccurence,
Brand, Model, Resolution
FROM Competitor
GROUP BY Brand, Model, Resolution
EDIT: Based on the comment, you could use a subquery or CTE to accomplish what you want. Something like:
WITH cteMaxDate AS (
SELECT SUM(CASE WHEN Type = 'ProAV' THEN 1 ELSE 0 END) AS TopProAV,
SUM(CASE WHEN Type = 'Disti' THEN 1 ELSE 0 END) AS TopDisti,
MAX(Date) AS LastOccurence,
Brand, Model, Resolution
FROM Competitor
GROUP BY Brand, Model, Resolution
)
SELECT md.TopProAV, md.TopDisti,
md.LastOccurentce,
md.Brand, md.Model, md.Resolution,
c.AdditionalColumn1, c.AdditionalColumn2
FROM cteMaxDate md
INNER JOIN Competitor c
ON md.Brand = c.Brand
AND md.Model = c.Model
AND md.Resolution = c.Resolution
AND md.LastOccurence = c.Date
Do you have a limited number of Types? In this case you can solve your problem using pivot
More specifically, for the table
Type Model
---- -----
A X
B X
C Y
A Z
NULL NULL
you run this query
Select Model, [A], [B], [C]
From
(select Model, Type
from dbo.Competitor) as SourceTable
PIVOT
(Count([Type]) for [Type] in ([A], [B], [C])) as PivotTable
to get
Model A B C
------ - - -
X 1 1 0
Y 0 0 1
Z 1 0 0