Merging rows SQL - Access - sql

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

Related

How to sum different criteria in 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')
)

SQL (sqlite) compare sums of rows grouped by another repeating row

I have a table like:
|------------------------|
|day name trees_planted|
|------------------------|
|1 | alice | 3 |
|2 | alice | 4 |
|1 | bob | 2 |
|2 | bob | 4 |
|------------------------|
I'm using SELECT name, SUM(trees_planted) FROM year2016 GROUP BY name to get:
name | trees_planted
alice | 7
bob | 6
But then I have another table from 2015 and I want to compare the results with the previous year, if for example Alice planted more trees in 2016 than in 2015 I'd get a result like this:
name | tree_difference
alice | -2 (if previous year she planted 5 trees, 5 -7 = -2)
bob | 0 (planted the same number of trees last year)
You could use a sub-query to get the records from both 2016 and 2015, but negate the values from 2016. Then group and sum like you already did:
SELECT name,
SUM(trees_planted) AS tree_difference
FROM (SELECT name, trees_planted
FROM year2015
UNION ALL
SELECT name, -trees_planted
FROM year2016
) AS years
GROUP BY name
This will also work for cases where a number is only given in one of the two years.
Assuming you can join using user field, you can do:
select a.name, a.tp, b.tp, a.tp - b.tp
from
(
(select name, SUM(trees_planted) tp from year2016 group by name) a
inner join
(select name, SUM(trees_planted) tp from year2015 group by name) b
using(name)
)
If you can't join on field user (you have different set of users in 2015 and 2016), it'll be easy to add the missing information by using a couple of union clauses.
Here's a link with artificial data to SQLFIDDLE to try the query.

Several conditions on the same table

I've inherited an excel file converted to a database and I try to figure out the people who went to several locations.
| Customer | email | ZIP | shop |
| John Smith | js#mail.com | 75016 | 1 |
| Mary King | mary#ymail.com | 97430 | 2 |
| John Smith | js#mail.com | 75016 | 3 |
| Ivan Turtle | ivan#mail.com | 56266 | 5 |
| Mary King | mary#ymail.com | 97430 | 5 |
| John Smith | js#mail.com | 75016 | 5 |
Eg : John Smith had been to 1, 3, 5
Mary King to 2, 3
I tried to use email as a key but can't figure out how to solve this one
assuming each row specifies a separate location,
select customer, count(*) as countOfLocation
from TABLE
group by customer
having count(*) > 1
order by countOfLocation desc
Is the simplest answer
I believe something like this will work for you.
Find all customers who have been to more than one shop, and then join back to get the details of each customer.
This will give back multiple rows per person, one for each shop they have been to. If all you care about is the names of customers, you can simply use the second SELECT
If you want one row per customer and a CSV of the shops, you will have to do a bit of joining.
SELECT a.*
FROM Customers a
INNER JOIN
-- Find all customers who have been to more than one shop.
(SELECT email
FROM Customers
GROUP BY email
HAVING COUNT(shop) > 1) b
ON a.email = b.email
Try with this if is Sql server:
select customer, count(distinct(shop))
from table
group by customer, shop
having count(distinct(shop)) > 1
or, you only want to know how many places they visited:
select customer, count(distinct(shop))
from table
group by customer, shop
if you want to show the user name and shop seperating by comma in one row use this
SELECT Customer
,STUFF((SELECT ', ' + CAST(shop AS VARCHAR(10)) [text()]
FROM 'ur table'
WHERE customer = t.customer
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') List_Output
FROM 'ur table' t
GROUP BY customer

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