Get the Data horizontally rather than vertically - sql

Consider the query :
Select Dealer, Sales from DEALERDATA
where period in (201106,201107)
This will give result as:
DEALER SALES
Dealer1 100000
Dealer1 200000
Dealer2 600000
Dealer2 700000
I want result as
DEALER SALES SALES
Dealer1 100000 200000
Dealer2 600000 700000
If any one can let me know how this can be achieved?
Many thanks,
Sharon....

For a few number of columns you can use CASE combined WITH sum
SELECT Dealer
, SUM(CASE WHEN period=201106 THEN Sales ELSE 0 END) sales201106
, SUM(CASE WHEN period=201107 THEN Sales ELSE 0 END) sales201107
FROM DEALERDATA
WHERE period IN (201106,201107)
GROUP BY Dealer

Related

Calculating percentages per product using aggregate functions and group by

I have a table with 5 rows representing two different products. The columns include the product, sales, discount. I'm trying to calculate the percentage of sales per product that included a discount. The table looks like this:
product
sales
discount
1
10
0
1
10
5
2
20
10
2
20
0
2
20
10
My results should look like the below (which I know because I've calculated this in Excel):
product
perc_discount
1
50.00
2
66.67
For each of the two products we are calculating the count of sales with discount divided by the total count of sales, so for product 1 it would be (1/2)*100 = 50.
My SQL code looks like the below:
SELECT
product,
(SELECT COUNT(*) FROM sales WHERE discount >0)/COUNT(*)*100 AS perc_discount
FROM sales
GROUP BY product
However, the result I'm getting is:
product
perc_discount
1
150.0
2
100.0
It seems to be calculating the total count of discounted sales in the table and diving it by the count of each product and I can't seem to figure out how to change it. Any ideas on how I can improve this?
Thanks.
How about conditional sum?
SQL> select product,
2 round(sum(case when discount > 0 then 1 else 0 end) / count(*) * 100, 2) perc_discount
3 from sales
4 group by product;
PRODUCT PERC_DISCOUNT
---------- -------------
1 50
2 66,67
SQL>
So: add 1 for every discount row per product. Divide that sum with total number of rows per product (that's count). Round the result to 2 decimals (so that it looks prettier).
You can use conditional aggregation. For example:
select
product,
100.0 * count(case when discount <> 0 then 'x' end) / count(*) as perc_discount
from sales
group by product

Calculating multiple averages across different parts of the table?

I have the following transactions table:
customer_id purchase_date product category department quantity store_id
1 2020-10-01 Kit Kat Candy Food 2 store_A
1 2020-10-01 Snickers Candy Food 1 store_A
1 2020-10-01 Snickers Candy Food 1 store_A
2 2020-10-01 Snickers Candy Food 2 store_A
2 2020-10-01 Baguette Bread Food 5 store_A
2 2020-10-01 iPhone Cell phones Electronics 2 store_A
3 2020-10-01 Sony PS5 Games Electronics 1 store_A
I would like to calculate the average number of products purchased (for each product in the table). I'm also looking to calculate averages across each category and each department by accounting for all products within the same category or department respectively. Care should be taken to divide over unique customers AND the product quantity being greater than 0 (a 0 quantity indicates a refund, and should not be accounted for).
So basically, the output table would like below:
...where store_id and average_level_type are partition columns.
Is there a way to achieve this in a single pass over the transactions table? or do I need to break down my approach into multiple steps?
Thanks!
How about using “union all” as below -
Select store_id, 'product' as average_level_type,product as id, sum(quantity) as total_quantity,
Count(distinct customer_id) as unique_customer_count, sum(quantity)/count(distinct customer_id) as average
from transactions
where quantity > 0
group by store_id,product
Union all
Select store_id, 'category' as average_level_type, category as id, sum(quantity) as total_quantity,
Count(distinct customer_id) as unique_customer_count, sum(quantity)/count(distinct customer_id) as average
from transactions
where quantity > 0
group by store_id,category
Union all
Select store_id, 'department' as average_level_type,department as id, sum(quantity) as total_quantity,
Count(distinct customer_id) as unique_customer_count, sum(quantity)/count(distinct customer_id) as average
from transactions
where quantity > 0
group by store_id,department;
If you want to avoid using union all in that case you can use something like rollup() or group by grouping sets() to achieve the same but the query would be a little more complicated to get the output in the exact format which you have shown in the question.
EDIT : Below is how you can use grouping sets to get the same output -
Select store_id,
case when G_ID = 3 then 'product'
when G_ID = 5 then 'category'
when G_ID = 6 then 'department' end As average_level_type,
case when G_ID = 3 then product
when G_ID = 5 then category
when G_ID = 6 then department end As id,
total_quantity,
unique_customer_count,
average
from
(select store_id, product, category, department, sum(quantity) as total_quantity, Count(distinct customer_id) as unique_customer_count, sum(quantity)/count(distinct customer_id) as average, GROUPING__ID As G_ID
from transactions
group by store_id,product,category,department
grouping sets((store_id,product),(store_id,category),(store_id,department))
) Tab
order by 2
;

updating transactions with preaggregated data

I have a transactions table. I need to update the table with a pre-aggregated value from another table and then roll these down to varying levels of granularity.
However, the final output is incorrect. Hoping someone here can help me figure out how to go about this.
Table A:
TransID BankName Location Region SaleType MonthlyPayment Weight
1 BOA Boston East F 3000 3
2 Mellon Pittsburgh East C 1000 3
3 BOA Boston East C 2000 2
4 BOA Boston East 1000 2
Table B
BanKname Location Region Sales
BOA Boston East 500
Mellon Pittsburgh East 1000
Desired Output structure
BankName Location Region SaleType AvgSales AvgMonthlyPayment
Issue is that when updating and doing the weighted average, each of the Boston transactions is getting the 500 sales. When added, total sales should be 1500 but is now 2500.
If I update Table A with Sales value from Table B, sales gets repeated for each saletype - so it throws off the final average sales.
update is this: (Added new column sales in A)
update a
set a.sales = b.sales
from tableA a join tableB b on a.bankname=b.bankname and
a.location=b.location and a.region = b.region
weighted average from A is calculated like this:
select bankname,location,region,saletype,
sum(case when sales is not null then sales*weight else 0
end)/sum(weight) as avgsales
, sum(case when monthlypayment is not null then monthlypayment*weight
else 0 end)/sum(weight) as avgmonthlyp
from tableA
group by bankname,location,region,saletype
For each saletype, the sales is updated with value thus increasing the final value by that fold.
How can I update sales so that BOA only gets 500 and Mellon only gets 1000 and the total # sales is at 1500?

Sub-Query with group by and Case Statement

I have two tables , one is Country table and another one is Threshold Table.
Country table has columns and data like this :
ID Country Count Year
00001 India 200 2011
00001 India 400 2013
00001 Japan 1000 2011
00001 Japan 550 2013
00001 China 400 2011
And the Threshold table has data like this :
ID Low Value High Value
00001 500 1000
That means if the Count >= 500 then Low , if the Count > 500 and < 1000 the Medium and if Count >= 1000 then High.
I want a result like this :
Country Count Threshold Low Value High Value
India 600 Medium 500 1000
Japan 1550 High 500 1000
China 400 Low 500 1000
So I want to write a SQL query .
I am already using this query :
SELECT C.Country,C.Count
,CASE WHEN C.Count <= T.Low_Value THEN 'Low' WHEN C.Count BETWEEN T.High_Value AND T.Low_Value THEN 'Medium' ELSE 'High' END AS Threshold,
T.Low_Value, T.High_Value FROM
(SELECT ID,Country,Sum(Count) AS Count
FROM Country
WHERE ID=00001
GROUP BY ID,Country) C
JOIN Threshold T
ON C.ID = T.ID
But this query is giving error.
Can anyone one please suggest me how to implement this ?
I am using Oracle
The error is ORA-00979 : not a GROUP BY expression
**This query is just for representation**
COUNT is a reserved word. Either pick a different alias or use double quotes around the alias.
SELECT C.Country,
C."Count",
CASE WHEN C."Count" <= T.Low_Value THEN 'Low'
WHEN C."Count" BETWEEN T.High_Value AND T.Low_Value THEN 'Medium'
ELSE 'High' END AS Threshold,
T.Low_Value,
T.High_Value
FROM (
SELECT ID,Country,Sum("Count") AS "Count"
FROM Country
WHERE ID=00001
GROUP BY ID,Country
) C
JOIN Threshold T
ON C.ID = T.ID
It can be done by using this :
SELECT Country
,Total
,CASE WHEN Total <= Low_Value THEN 'Low'
WHEN Total BETWEEN Low_Value AND High_Value THEN 'Medium'
ELSE 'High' END AS Threshold
FROM (SELECT ID
,Country
,Low_Value
,High_Value
,SUM(Count) Total
FROM (SELECT C.ID
,C.Country
,C.Count
,T.Low_Value
,T.High_Value
FROM Country C JOIN Threshold T
ON C.ID=T.ID
WHERE C.ID =00001)
GROUP BY Country,Low_Value,High_Value)

Sql query Solution

I have a query as follows.
select strftime('%Y-%m',A.traDate) as Month,sum(A.TraAmt) as Total,C.GroupType from
TransactionTbl A left join TransactionCategory B on A.CategoryID = B.CategoryID left join
CategoryGroup C on B.CatGRoupID=C.CatGRoupID where A.UserID=1 and A.ProfileID=1 and
date(A.TraDate) between date('2009-12-01') and date('2010-11-01') group by C.GroupType,
strftime('%m',A.traDate) order by Month
Above query gives result as follows,
Month Total C.GroupType
----- ----- -----------
2009-12 4100 Expense
2009-12 8000 Income
2010-01 200 Expense
2010-01 2000 Income
2010-02 3500 Expense
2010-02 7500 Income
I want solution like this.
Month Income Expense
----- ----- -----------
2009-12 8000 4100
2010-01 8000 200
2010-02 7500 3500
I am trying hard to get output like this, but I could find any kind of solution.
This is one way of achieving what you want:
SELECT
T1.Month,
SUM(CASE T1.GROUPTYPE WHEN 'Income' THEN T1.TOTAL ELSE 0 END) AS Income,
SUM(CASE T1.GROUPTYPE WHEN 'Expense' THEN T1.TOTAL ELSE 0 END) AS Expense
FROM (/* Your query here */) AS T1
GROUP BY T1.Month