How to sum different criteria in SQL? - sql

I have data that looks like this in Redshift:
+-------------+------------+---------+
| Employee_ID | Manager_ID | Revenue |
+-------------+------------+---------+
| 123 | 123 | 1015.24 |
| 541 | 123 | 5587.23 |
+-------------+------------+---------+
I want to write a query that sums manager revenue whenever a Manager_ID is inputted and sums employee revenue whenever an Employee_ID is inputted. Currently, I have a query that looks like this and I have to run it twice:
SELECT
sum(revenue) as revenue
FROM
employee_rev r
WHERE
r.manager_id in ('123','124') --I change this to employee_ID the second time around
If it helps, there is another table like this:
+-------------+------------------------+
| Employee_ID | Role |
+-------------+------------------------+
| 123 | Manager |
| 541 | Individual Contributor |
+-------------+------------------------+
Thank you so much for your time, this seemed really simple and now I'm pretty frustrated.

I think you can just do:
SELECT sum(revenue) as revenue
FROM employee_rev r
WHERE 123 in (r.employee_id, r.manager_id);
That is, for a given id, look in both columns. An employee should never be in the manager column, so this would appear to do what you want.
EDIT:
For multiple ids, you would have to test independently. Either:
WHERE 123 IN (r.employee_id, r.manager_id) OR
456 IN (r.employee_id, r.manager_id)
or:
WHERE r.employee_id in (123, 456) OR
r.manager_id in (123, 456)

Use union to add two selects into one 'table', then sum it. I think this should work
SELECT sum(result) from (
SELECT
sum(revenue) as result
FROM
employee_rev r
WHERE
r.manager_id in ('123')
UNION ALL
SELECT
sum(revenue) as result
FROM
employee_rev r
WHERE
r.employee_id in ('124')
)

Related

How to query to capture recency and scale in one query?

I've built a query that calculates the number of ids from a table, per url_count.
with cte as (
select id, count(distinct.url) url_count
from table
group by id
)
select sum(if(url_count >= 1,1,0) scale
from cte
union all
select sum(if(url_count >= 2,1,0) scale
from cte
union all
select sum(if(url_count >= 3,1,0) scale
from cte
union all
select sum(if(url_count >= 4,1,0) scale
from cte
union all
select sum(if(url_count >= 5,1,0) scale
from cte
The query above says; "Give me the list of ids and the number of urls they each go to, then accumulate the number of ids who have gone to [1-5] or more urls"
It's ofc a tedious method, but works and outputs something like;
---------
| scale |
---------
|1213432|
|867554 |
|523523 |
|342232 |
|145889 |
---------
From this table, I also have a date field on the last 5 days which I'm working on adding into this query. Thus lies the challenge; Trying to add a second layer of information to the query; i.e. Recency. Been working on multiple approaches to building a query that outputs all the combinations of different scales, per the date.
The sort of output I've imagined is a pivot table which presents something like;
-------------------------------------------------------------
| date | url_co1 | url_co2 | url_co3 | url_co4 | url_co5|
-------------------------------------------------------------
|2020-01-05| 1213432 | 1112321 | 984332 | 632131 | 234124 |
|2020-01-04| 1012131 | 934242 | 867554 | 533242 | 134234 |
| ... | ... | ... | ... | ... | ... |
| ... | ... | ... | ... | ... | ... |
| ... | ... | ... | ... | ... | ... |
-------------------------------------------------------------
Where url_co[1-5] represents the number of ids that visited [1-5] or more urls and dates gives up the date that volume was captured. No idea how to write that because once I query:
with cte as (
select id, date, count(distinct.url) url_count
from table
group by id, date
)
I've aggregated to per id, per date, which therefore something goes wrong. =/
Hope that all made sense!
Please, please help! I would appreciate some guidance.
There must be a methodology for getting the combination of volumes per recency that I've missed!
I don't really follow the full question, but the first query can be simplified to:
select url_count, count(*) as this_count,
sum(url_count) over (order by url_count desc) as descending_count
from (select id, count(distinct url) as url_count
from table
group by id
) t
group by url_count
order by url_count;

Totaling Expenses by Employee ID with SQL

I am working on a SELECT query to generate a specific output file that will be sent between systems relating to company expense reports. I am using data from two tables and am needing to generate a total value each employee owes the company. My query is similar to the following:
SELECT emp.Employee_ID,
invoice.Date,
(SELECT TOP 1 Invoice_Amount from invoice where....) as Amount_Owed
FROM employee as emp
INNER JOIN invoice_data as invoice
on invoice.employee_id = emp.employee_id
GROUP BY emp.Employee_ID, invoice.Date
Now obviously I know there is something wrong with this query, because I am getting results such as the following:
Employee_ID | Date | Amount_Owed
-------------------------------------
1000001 | 20190904 | 15.00
1000001 | 20190905 | 15.00
1000001 | 20190906 | 15.00
1000025 | 20190904 | 25.99
1000025 | 20190905 | 25.99
1000025 | 20190906 | 25.99
How do I change my query so that I can essentially get the invoice total for each employee by date? I have tried change the SELECT in the subquery to SELECT sum(Invoice_Amount from invoice where....), but then I always get errors from SSMS saying that it returns more than a single record so that does not seem to be valid. That same error also prevents me from just doing a SELECT without the "TOP 1" in the subquery.
This is probably a fairly simple issue, but I have spun my wheels too long without any successful attempts, so I would appreciate suggestions as to how I can get the data I want.
Doesn't a simple aggregation work?
SELECT e.Employee_ID, id.Date,
SUM(id.Invoice_Amount) as Amount_Owed
FROM employee e INNER JOIN
invoice_data id
on id.employee_id = e.employee_id
GROUP BY e.Employee_ID, id.Date

Merging rows SQL - Access

I have this table on MS Access:
Name | Week | Manager | Sales
John | 201409 | Marcelo | 53
John | 201410 | Marcelo | 20
John | 201410 | Raquel | 30
John | 201411 | Raquel | 53
I have to merge Week 201410 by the max Sales and choose which Manager. After this I'd like to sum the Total Sales for this two and make like this:
Name | Week | Manager | Sales
John | 201409 | Marcelo | 53
John | 201410 | Raquel | 50
John | 201411 | Raquel | 53
Could anybody help me? I tried a lot of SQL and couldn't do nothing useful.
You can try this:
SELECT [Name], [Week], [Manager], SUM([Sales]) as Sales1
From [YourTable]
GROUP BY [Name], [Week], [Manager]
I did not test this so let me know what errors you get.
If each row had a unique identifier (Primary Key), it would be a lot simpler. However, you work with the data you have, not with the data you wish you had, so here's my circuitous way of accomplishing it. You could combine this all into one query and avoid using temporary tables; I split it out this way to make it convenient to understand, rather than being concise.
First, extract the highest Sales for each Name-Week combination:
SELECT Name, Week, MAX(Sales)
INTO #MaxSales
FROM [YourTable]
GROUP BY Name, Week
Use this information to get the Manager that you should use for each week (We use TOP 1 to resolve the case where two managers have the same sales for the same Name/Week; I'm not sure how you would want to resolve this.):
SELECT Name, Week, Manager
INTO #MaxSalesManager
FROM [YourTable]
INNER JOIN #MaxSales
ON [YourTable].Name = #MaxSales.Name
AND [YourTable].Week = #MaxSales.Week
WHERE [YourTable].Sales = #MaxSales.Sales
Now you can extract the information you need:
SELECT [YourTable].Name, [YourTable].Week, #MaxSalesManager.Manager, SUM([YourTable].Sales)
FROM [YourTable]
INNER JOIN #MaxSalesManager
ON [YourTable].Name = #MaxSalesManager.Name
AND [YourTable].Week = #MaxSalesManager.Week
GROUP BY [YourTable].Name, [YourTable].Week, #MaxSalesManager.Manager
Hope this helps!
EDIT:
Combining them all into one query:
SELECT [YourTable].Name,
[YourTable].Week,
#MaxSalesManager.Manager,
SUM([YourTable].Sales)
FROM [YourTable]
INNER JOIN
(SELECT Name, Week, Manager
FROM [YourTable]
INNER JOIN
(SELECT Name, Week, MAX(Sales)
FROM [YourTable]
GROUP BY Name, Week) AS #MaxSales
ON [YourTable].Name = #MaxSales.Name
AND [YourTable].Week = #MaxSales.Week
WHERE [YourTable].Sales = #MaxSales.Sales) AS #MaxSalesManager
ON [YourTable].Name = #MaxSalesManager.Name
AND [YourTable].Week = #MaxSalesManager.Week
GROUP BY [YourTable].Name, [YourTable].Week, #MaxSalesManager.Manager

SQL: Select distinct sum of column with max(column)

I have a salary table like this:
id | person_id | start_date | pay
1 | 1234 | 2012-01-01 | 3000
2 | 1234 | 2012-05-01 | 3500
3 | 5678 | 2012-01-01 | 5000
4 | 5678 | 2013-01-01 | 6000
5 | 9101 | 2012-09-01 | 2000
6 | 9101 | 2014-04-01 | 3000
7 | 9101 | 2011-01-01 | 1500
and so on...
Now I want to query the sum of the salaries of a specific month for all persons of a company.
I already have the ids of the persons who worked in the specific month in the specific company, so I can do something like WHERE person_id IN (...)
I have some problems with the salaries query though. The result for e.g. the month 2012-08 should be:
10000
which is 3500+5000+1500.
So I need to find the summed up pay value (for all persons in the IN clause) for the maximum start_date <= the specific month.
I tried various INNER JOINS but it's been a long day and I can't think straight at the moment.
Any hint is highly appreciated.
You need to get the active record. This following does this by calculating the max start date before the month in question:
select sum(s.pay)
from (select person_id, max(start_date) as maxstartdate
from salary
where person_id in ( . . . ) and
start_date < <first day of month of interest>
group by person_id
) p join
salary s
on s.person_id = p.person_id and
s.maxstartdate = p.start_date
You need to fill in the month and list of ids.
You can also do this with ranking functions, but you don't specify which SQL engine you are using.
You have to use group by for these things....
select person_id,sum(pay) from salary where person_id in(...) group by person_id
may it will helps you.....

MIN() Function in SQL

Need help with Min Function in SQL
I have a table as shown below.
+------------+-------+-------+
| Date_ | Name | Score |
+------------+-------+-------+
| 2012/07/05 | Jack | 1 |
| 2012/07/05 | Jones | 1 |
| 2012/07/06 | Jill | 2 |
| 2012/07/06 | James | 3 |
| 2012/07/07 | Hugo | 1 |
| 2012/07/07 | Jack | 1 |
| 2012/07/07 | Jim | 2 |
+------------+-------+-------+
I would like to get the output like below
+------------+------+-------+
| Date_ | Name | Score |
+------------+------+-------+
| 2012/07/05 | Jack | 1 |
| 2012/07/06 | Jill | 2 |
| 2012/07/07 | Hugo | 1 |
+------------+------+-------+
When I use the MIN() function with just the date and Score column I get the lowest score for each date, which is what I want. I don't care which row is returned if there is a tie in the score for the same date. Trouble starts when I also want name column in the output. I tried a few variation of SQL (i.e min with correlated sub query) but I have no luck getting the output as shown above. Can anyone help please:)
Query is as follows
SELECT DISTINCT
A.USername, A.Date_, A.Score
FROM TestTable AS A
INNER JOIN (SELECT Date_,MIN(Score) AS MinScore
FROM TestTable
GROUP BY Date_) AS B
ON (A.Score = B.MinScore) AND (A.Date_ = B.Date_);
Use this solution:
SELECT a.date_, MIN(name) AS name, a.score
FROM tbl a
INNER JOIN
(
SELECT date_, MIN(score) AS minscore
FROM tbl
GROUP BY date_
) b ON a.date_ = b.date_ AND a.score = b.minscore
GROUP BY a.date_, a.score
SQL-Fiddle Demo
This will get the minimum score per date in the INNER JOIN subselect, which we use to join to the main table. Once we join the subselect, we will only have dates with names having the minimum score (with ties being displayed).
Since we only want one name per date, we then group by date and score, selecting whichever name: MIN(name).
If we want to display the name column, we must use an aggregate function on name to facilitate the GROUP BY on date and score columns, or else it will not work (We could also use MAX() on that column as well).
Please learn about the GROUP BY functionality of RDBMS.
SELECT Date_,Name,MIN(Score)
FROM T
GROUP BY Name
This makes the assumption that EACH NAME and EACH date appears only once, and this will only work for MySQL.
To make it work on other RDBMSs, you need to apply another group function on the Date column, like MAX. MIN. etc
SELECT T.Name, T.Date_, MIN(T.Score) as Score FROM T
GROUP BY T.Date_
Edit: This answer is not corrected as pointed out by JNK in comments
SELECT Date_,MAX(Name),MIN(Score)
FROM T
GROUP BY Date_
Here I am using MAX(NAME), it will pick one name if two names were found with the same goal numbers.
This will find Min score for each day (no duplicates), scored by any player. The name that starts with Z will be picked first than the name that starts with A.
Edit: Fixed by removing group by name