SQL Server: how to divide the result of sum of total for every customer id - sql

I have 4 tables like this (you can ignore table B because this problem did not use that table)
I want to show the sum of 'total' for each 'sales_id' from table 'sales_detail'
What I want (the result) is like this:
sales_id | total
S01 | 3
S02 | 2
S03 | 4
S04 | 1
S05 | 2
S05 | 3
I have tried with this query:
select
sum(total)
from
sales_detail
where
sales_id = any (select sales_id
from sales
where customer_id = any (select customer_id
from customer)
)
but the query returns a value if 15 because they are the sum of those rows of data.
I have tried to use "distinct" before sum
and the result is [ 1, 2, 3 ] because those are distinct of those rows of data (not sum of each sales_id)
It's all about subquery

You are just so far off track that a simple comment won't help. Your query only concerns one table, sales_detail. It has nothing to do with the other two.
And, it is just an aggregation query:
select sd.sales_id, sum(sd.total)
from sales_detail sd
group by sd.sales_id;
This is actually pretty close to what the question itself is asking.

Related

Count all of a column where value is 2 and sum this value with price

I'm doing with Northwind database where I use the Products table. I need to count all of the rows where Category_Id is 2 and sum the amount with the prices.
Here's the example of a table shortly:
Category_ID | Unit Price
1 | 2,90
2 | 3,70
3 | 4,90
2 | 1,90
5 | 0,90
2 | 2,90
There are 3 rows where category_Id is 2. How to sum this 3 with that rows Unit price?
3,70 + 1,90 + 2,90 = 8,50
So the answer I need is 8,50 but I have no idea how to get that amount with a SQL query.
Does someone know?
you can get the aggregated values for all Ids using
Select Categeory_Id, sum([Unit Price]) Total, count(*) Qty
from Products
group by Category_Id
or just a specific total such as
select sum([Unit Price]) total
from products
where category_Id=2

Oracle SQL Help Data Totals

I am on Oracle 12c and need help with the simple query.
Here is the sample data of what I currently have:
Table Name: customer
Table DDL
create table customer(
customer_id varchar2(50),
name varchar2(50),
activation_dt date,
space_occupied number(50)
);
Sample Table Data:
customer_id name activation_dt space_occupied
abc abc-001 2016-09-12 20
xyz xyz-001 2016-09-12 10
Sample Data Output
The query I am looking for will provide the following:
customer_id name activation_dt space_occupied
abc abc-001 2016-09-12 20
xyz xyz-001 2016-09-12 10
Total_Space null null 30
Here is a slightly hack-y approach to this, using the grouping function ROLLUP(). Find out more.
SQL> select coalesce(customer_id, 'Total Space') as customer_id
2 , name
3 , activation_dt
4 , sum(space_occupied) as space_occupied
5 from customer
6 group by ROLLUP(customer_id, name, activation_dt)
7 having grouping(customer_id) = 1
8 or (grouping(name) + grouping(customer_id)+ grouping(activation_dt)) = 0;
CUSTOMER_ID NAME ACTIVATIO SPACE_OCCUPIED
------------ ------------ --------- --------------
abc abc-001 12-SEP-16 20
xyz xyz-001 12-SEP-16 10
Total Space 30
SQL>
ROLLUP() generates intermediate totals for each combination of column; the verbose HAVING clause filters them out and retains only the grand total.
What you want is a bit unusual, as if customer_id is integer, then you have to cast it to string etc, but it this is your requirement, then if be achieved this way.
SELECT customer_id,
name,
activation_dt,
space_occupied
FROM
(SELECT 1 AS seq,
customer_id,
name,
activation_dt,
space_occupied
FROM customer
UNION ALL
SELECT 2 AS seq,
'Total_Space' AS customer_id,
NULL AS name,
NULL AS activation_dt,
sum(space_occupied) AS space_occupied
FROM customer
)
ORDER BY seq
Explanation:
Inner query:
First part of union all; I added 1 as seq to give 1
hardcoded with your resultset from customer.
Second part of union
all: I am just calculating sum(space_occupied) and hardcoding other
columns, including 2 as seq
Outer query; Selecting the data
columns and order by seq, so Total_Space is returned at last.
Output
+-------------+---------+---------------+----------------+
| CUSTOMER_ID | NAME | ACTIVATION_DT | SPACE_OCCUPIED |
+-------------+---------+---------------+----------------+
| abc | abc-001 | 12-SEP-16 | 20 |
| xyz | xyz-001 | 12-SEP-16 | 10 |
| Total_Space | null | null | 30 |
+-------------+---------+---------------+----------------+
Seems like a great place to use group by grouping sets seems like this is what they were designed for. Doc link
SELECT coalesce(Customer_Id,'Total_Space') as Customer_ID
, Name
, ActiviatioN_DT
, sum(Space_occupied) space_Occupied
FROM customer
GROUP BY GROUPING SETS ((Customer_ID, Name, Activation_DT, Space_Occupied)
,())
The key thing here is we are summing space occupied. The two different grouping mechanisms tell the engine to keep each row in it's original form and 1 records with space_occupied summed; since we group by () empty set; only aggregated values will be returned; along with constants (coalesce hardcoded value for total!)
The power of this is that if you needed to group by other things as well you could have multiple grouping sets. imagine a material with a product division, group and line and I want a report with sales totals by division, group and line. You could simply group by () to get grand total, (product_division, Product_Group, line) to get a product line (product_Divsion, product_group) to get a product_group total and (product_division) to get a product Division total. pretty powerful stuff for a partial cube generation.

Row number in query result

I have query to get firms by theirs sales last year.
select
Name,
Sale
from Sales
order by
Sale DESC
and I get
Firm 2 | 200 000
Firm 1 | 190 000
Firm 3 | 100 000
And I would like to get index of row in result. For Firm 2 I would like to get 0 (or 1), for Firm 3 1 (or 2) and etc. Is this possible? Or at least create some sort of autoincrement column. I can use even stored procedure if it is needed.
Firebird 3.0 supports row_number() which is the better way to do this.
However for Firebird 2.5, you can get what you want with a correlated subquery:
select s.Name, s.Sale,
(select count(*) from Sales s2 where s2.sale >= s.sale) as seqnum
from Sales s
order by s.Sale DESC;

How to get the count of distinct values until a time period Impala/SQL?

I have a raw table recording customer ids coming to a store over a particular time period. Using Impala, I would like to calculate the number of distinct customer IDs coming to the store until each day. (e.g., on day 3, 5 distinct customers visited so far)
Here is a simple example of the raw table I have:
Day ID
1 1234
1 5631
1 1234
2 1234
2 4456
2 5631
3 3482
3 3452
3 1234
3 5631
3 1234
Here is what I would like to get:
Day Count(distinct ID) until that day
1 2
2 3
3 5
Is there way to easily do this in a single query?
Not 100% sure if will work on impala
But if you have a table days. Or if you have a way of create a derivated table on the fly on impala.
CREATE TABLE days ("DayC" int);
INSERT INTO days
("DayC")
VALUES (1), (2), (3);
OR
CREATE TABLE days AS
SELECT DISTINCT "Day"
FROM sales
You can use this query
SqlFiddleDemo in Postgresql
SELECT "DayC", COUNT(DISTINCT "ID")
FROM sales
cross JOIN days
WHERE "Day" <= "DayC"
GROUP BY "DayC"
OUTPUT
| DayC | count |
|------|-------|
| 1 | 2 |
| 2 | 3 |
| 3 | 5 |
UPDATE VERSION
SELECT T."DayC", COUNT(DISTINCT "ID")
FROM sales
cross JOIN (SELECT DISTINCT "Day" as "DayC" FROM sales) T
WHERE "Day" <= T."DayC"
GROUP BY T."DayC"
try this one:
select day, count(distinct(id)) from yourtable group by day

how to find percentage without calculating manually?

Thanks you for looking.I am new to tsql and dont know how to proceed. I have a table with 10 different companies and 20 department for each(the departments are same for all the companies).
I am trying to calculate percentage of expenses for each department and want an extra column 'Percentage' to be displayed in the result.
please note that for every company the first department is totalcompexpenses which is just the total expenses of the company for all the department combined and dont need to calculate that and should be calculated from the next row.
Is it possible to do this by using while loop or any other way instead of doing it manually for each one of them?
ID |Company_name| Department |Expenses | Percentage
1 |Company1 |TotalComp1Expenses |50000 | -
2 |Company1 |Department1 |4000 | ?
3 |Company1 |Department2 |8000 | ?
4 |Company1 |Department3 |8000 | ?
5 |Company1 |Department4 |7000 | ?
6 |Company1 |Department5 |10000 | ?
...
11 |Company2 |TotalComp2Expenses |100000 | -
12 |Company2 |Department1 |6000 | ?
13 |Company2 |Department2 |5000 | ?
15 |Company2 |Department3 |8000 | ?
15 |Company2 |Department4 |7000 | ?
16 |Company2 |Department5 |10000 | ?
...
21 |Company3 |TotalComp3Expenses |70000 | -
22 |Company3 |Department1 |2000 | ?
23 |Company3 |Department2 |7000 | ?
24 |Company3 |Department3 |9000 | ?
25 |Company3 |Department4 |8000 | ?
26 |Company3 |Department5 |10000 | ?
...
I think the clearest way is to use window functions. If you want the percentages based on the Total% columns, then you can do it as:
select ID, Company_name, Department, Expenses,
(100.0* Expenses /
max(case when Department like 'Total%Expenses' then Expenses end) over
(partition by Company_Name)
) as Percentage
from t;
You can also do this as a sum of the non-Total expenses:
select ID, Company_name, Department, Expenses,
(100.0* Expenses /
max(case when Department not like 'Total%Expenses' then Expenses end) over
(partition by Company_Name)
) as Percentage
from t;
The window function is like an aggregation function, but without the aggregation. The sum for each group is added as an additional column on each row. The definition of the grouping is based on the partition by clause.
Add this column to the query
Expenses * 200.0 / SUM(expenses) over (partition by company_name) as PercentageExepenses
You have to multiply expenses by 200.0 to take into account that you already have the total for the company and therefore double count.
if you self-join and thus have the total of each company in a separate column, you can calculate the percentages. the company total has 100% then, which i deem as correct
select
id
, company_name
, department
, expenses
, expenses/total*100 as percentage
from table_expenses tbx
inner join
(select
company_name
, sum(expenses/2) as expenses
from table_expenses
group by
company_name
) sums
on
(tbx.company_name = sums.company_name)
EDIT:
Are you actually storing the company totals in your database? If, so then this should work for the CTE:
select
compname,
expense as CompExp
from
<YourTable>
where
Department like 'Total%'
But I don't know why you would want to store subtotals like that.
Using your "table" as an example:
;with CompTotal as (
select
compname,
sum(expenses) as CompExp
from
<YourTable>
group by CompName)
select
C.CompName,
Department,
CompTotal.CompExp,
sum(Expenses)as DeptEexpense,
(sum(Expenses) / (CompTotal.CompExp * 1.0)) * 100 as Pct
from
<YourTable> C
inner join
CompTotal
on C.CompName = CompTotal.CompName
group by
C.CompName,
Department,
CompTotal.CompExp
The CTE gives us totals by company. We then join that back to the original table on company name, and total up by Department. Then just regular math gives us the percentage of each department of it's company total.
(SQLFiddle is down, or I'd link to a full example there)