Using select distinct with sum - sql

I am not sure if what I want can be done but basically, I have a homework where I am supposed to come up with sql statements to filter through a database of a made up TCM company in any way. I wanted to filter branch to see which branch earns the most revenue.
but I am stuck here because I don't know how to filter it.
select distinct b.branch_ID, t.fees
from treatment t,branch b, appointment a, appointment_treatment at
where t.treatment_ID = at.treatment_ID
and at.appt_ID = a.appt_ID
and b.branch_ID = a.branch_ID
The result is like so.
branch revenue
BR001 30.00
BR001 45.00
BR001 75.00
BR002 28.00
BR002 40.00
BR002 60.00
BR003 28.00
BR003 60.00
BR004 28.00
However, what I want is:
branch (sum of) revenue for each branch
BR001 30.00
BR002 45.00
BR003 75.00
BR004 28.00
BR005 40.00
but I can't think of a way to make this work!

If I understood you problem correctly, you can use GROUP BY clause combined with SUM function to achieve what you want, like this:
select
b.branch_ID, sum(t.fees)
from
treatment t,branch b, appointment a, appointment_treatment at
where
t.treatment_ID = at.treatment_ID
and at.appt_ID = a.appt_ID
and b.branch_ID = a.branch_ID
group by
b.branch_ID

Related

Need help to build a sales funnel report by sql query

I have created a view for sales.In this view, there are relations among lead, opportunity and quotation. We can see not every lead turns to opportunity and quotation.
LeadID OfferingID QuotationID Product Salesperson Department Date Salesprice
L1 O1 Q1 X001 Mr.X Machine Sales 11-01-2011 100
L2 O2 Q2 X002 Mr.Y Marine Sales 10-02-2011 200
L3 O3 X003 Mr.Z Engine Sales 11-03-2011 300
L4 O4 Q3 X004 Mr.P Parts Sales 13-04-2011 50
L5 X001 Mr.X Machine Sales 20-05-2012 100
L6 O5 X001 Mr.X Machine Sales 30-06-2012 100
My final output for the sales funnel for all department will be like [total number of leads (6)]->[total number of offering(5)]->[total number of quotations(3)].
If i want to filter it by 'Machine Sales' department ,the funnel will be like:
[total number of leads (3)]->[total number of offering(2)]->[total number of quotations(1)]..
i need to be able to filter the funnel by date,salesperson,product and department.please help me to build this sales funnel query.
i will then visualize the data in microsoft powerbi after implementing the query which will be in a funnel shape.
Is there anything stopping you from feeding this data directly into Power BI?
I think you might be over-engineering this problem, and creating another table/view on you database that you'll have to remember/manage.
Leads = COUNT('YourTableNameHere'[LeadID])
Offers = COUNT('YourTableNameHere'[OfferID])
Quotes = COUNT('YourTableNameHere'[QuoteID])
This is very straightforward conditional aggregation with a group by:
select date
,salesperson
,etc
,sum(case when LeadID <> '' then 1 end) as NumberOfLeads
,etc
from YoutTable
group by date
,salesperson
,etc
If your LeadID, OfferingID and QuotationID columns have null values where there is no data you don't even need the conditional within the aggregate and can instead just use count as the null values are ignored:
select ...
,count(LeadID) as NumberOfLeads
,...
etc
I think you want:
select department, count(leadid) as num_leads, count(offeringid) as numoffers,
count(distinct quotationid) as numquotations
from t
group by department;
I don't think count(distinct) is needed for the first two columns, but your data has no examples of duplicates so it is unclear.

Select columns value based on logic applied on the rows

It is a self-join I need, but I'm having difficulty with this problem and I hope someone can help me.
I have a table with MAT_CODE, MATERIAL and VENDOR and I am trying to generate a new column with NEW_MATCODE as per the below scenario.
Sample Data :
NEW_MATCODE MAT_CODE MATERIAL VENDOR WIN_VENDOR
X-043223065 GP002134 GP002134
3065 X-043223065 USD005 P10011
3065 3065 X-043223065 EUR003 P10011
4567 4567 X-023065 UD00005 UD00005
4567 X-023065 DF00388 UD00005
4321 X-04065 P24005 P24005
4321 4321 X-04065 D41111 P24005
4321 X-04065 D46732 P24005
X-0432065 US7800 D0230005
X-0432065 EUR234 D067805
123 123 X-04322 P0008 P0008
123 1234 X-04322 EU0323 P0008
123 1262 X-04322 EUR0032 P0008
2345 2345 X-04322 DFGH322 P12008
123456 123456 X-04322 EUR00323 P12008
1113 1113 X-04322 EUR0032 P12008
Logic for 1,2 and 3 sets of data:
Pick up the MATERIAL AND WIN_VENDOR combination and get the unique MAT_CODE and apply it across all MATERIAL- WIN_VENDOR combinations as the NEW_MATCODE
Logic for 4th set :
If no combination for MAT_CODE exists then leave it as-is
Logic for 5th set:
When different MAT_CODE exists for the same MATERIAL and WIN_VENDOR combination, apply NEW_MATCODE as the MAT_CODE from MATERIAL - VENDOR where VENDOR = WIN_VENDOR
Logic for 6th set:
When different MAT_CODE exists for the same MATERIAL and WIN_VENDOR combination, and VENDOR <> WIN_VENDOR leave MAT_CODE as-is.
Hope it is clear. Any help would be appreciated.
Thanks.
I think the following query will get you most of the way to what you are looking for:
SELECT mat_code, material, vendor, win_vendor,
CASE
WHEN COUNT(DISTINCT mat_code) OVER (PARTITION BY material, win_vendor) = 0 THEN mat_code
WHEN COUNT(DISTINCT mat_code) OVER (PARTITION BY material, win_vendor) = 1 THEN MAX(mat_code) OVER (PARTITION BY material, win_vendor)
ELSE NVL((SELECT sub.mat_code FROM material_info sub WHERE sub.material = mi.material AND sub.vendor = sub.win_vendor), mi.mat_code)
END AS NEW_MAT
FROM material_info mi;
The case statement is making use of the analytical functions to handle cases 1-4. The else branch is attempting to grab Case 5 and if it isn't found defaulting to Case 6.

Extract different rates associated with one ID

I have a single loan database with a user_id, loan_id, interest_rate, loan_date and other stuff that isn't relevant here.
How would I extract all the user_id's for those who took out at least two loans, and had the later ones at better interest rates.
select member_id, Annual_interest_rate, count(*)
from (select member_id, Annual_interest_rate, count(*)
from loan_book
group by member_id
having count(*)>1)
group by member_id, Annual_interest_rate
It shows the stuff from the subquery but with count 1 instead of count 2
Does the subquery destroy the necessary info? is there a way to write it as one query?
sample table
user loan air date
0001 2345 2.6 09/03
0002 1346 2.6 03/05
0003 1118 3.7 05/03
0002 6756 1.2 05/08
0003 1286 3.2 01/10
0001 2222 3.0 09/11
the result would be:
user loan air date
0002 6756 2.6 05/08
0003 1286 3.2 01/10
as those were the two loans that had better interest rates than their predecessors. If there are more than two then the ones that were better than one of their predeccessors should show
Here is a query that might work or at least the approach might help with some ideas.
SELECT LB2.*
FROM loan_book LB1 INNER JOIN loan_book LB2
ON LB1.user_id = LB2.user_id
AND LB1.loan_id != LB2.loan_id
AND LB1.loan_date < LB2.loan_date
AND LB1.interest_rate > LB2.interest_rate
You join the table with itself so each user will have two loans in each row and then you can do the necessary comparisons and groupings from the result. Hope this helps.

Combining Data from Two Tables into One Row

I've read around quite a bit for a solution to my problem but I can't seem to get it to work. It seems like a simple problem but I'm not getting the result set I want.
I'm working on a report that needs to pull from two tables and essentially create one row of data for each employee. The file needs to be uploaded to a healthcare vendor.
Here is an example of the data
Table1: EmployeeCheckDeduction
Employee ID Deduction Amount Check Date
1234 50.00 6/30/2015
1234 50.00 7/15/2015
4567 100.00 6/30/2015
4567 100.00 7/15/2015
9876 75.00 6/30/2015
9876 75.00 7/15/2015
Table2: EmployerContribution
Employee ID Contribution Amount Check Date
1234 25.00 6/30/2015
1234 30.00 7/15/2015
4567 50.00 6/30/2015
4567 60.00 7/15/2015
Part of the problem is that not every record in Table1 will have a corresponding match in Table 2. If they are maxed out on contributions, they won't receive one on that pay. What I want is a result set that looks like this:
Employee ID Deduction Amount Contribution Amount Check Date
1234 50.00 25.00 6/30/2015
1234 50.00 30.00 7/15/2015
4567 100.00 50.00 6/30/2015
4567 100.00 60.00 7/15/2015
9876 75.00 0.00 6/30/2015
9876 75.00 0.00 7/15/2015
No matter how I try and join, it's just duplicating data. I've tried using subqueries or distinct records and no matter what I try, it's not giving me what I want. I can't figure out what I'm doing wrong.
Edit. See links below for dataset results.
http://s000.tinyupload.com/index.php?file_id=01551050904538574848
http://s000.tinyupload.com/index.php?file_id=63978789937644749322
http://s000.tinyupload.com/index.php?file_id=28700836121558977952
I think part of the problem is that in the Employee Check Deduction table there is a specific deduction code that I'm pulling out. In the employer deduction table that code also exists. However, whenever I try and add the join on those 2 fields in addition to employee ID and check date, it doesn't return results from the employees who have a deduction amount in the employee check deduction table when they don't have a corresponding record in the Employer Contribution Table. I hope that helps.
select a.employee_id, a.deduction_amount, b.contribution_amount,
a.check_date
from employeecheckdeduction a join employercontribution b
on a.employee_id = b.employee_id
and a.check_date = b.check_date
Try this by renaming the columns if necessary. You should join on employed and checkdate.
SELECT a.EMPLID as EmployeeID, a.AL_AMOUNT as EmployeeContribution, ISNULL(b.AL_AMOUNT, 0) AS EmployerContribution, a.CHECK_DT
FROM PS_AL_CHK_DED as a
LEFT JOIN PS_AL_CHK_MEMO as b ON a.EMPLID = b.EMPLID AND a.CHECK_DT = b.CHECK_DT
WHERE a.AL_DEDCD = 'H'
ORDER BY a.CHECK_DT
The problem here is that you are dealing with TWO different things:
a) You want a FULL list of all employees who have ever had a contribution AND/OR a deduction
b) You then want to display it in one row
While there are many ways to go about this, the first thing would be two separate out those two and handle them.
Also it is not clear if you want to GROUP BY the employee ID or if you want to see a full history. If you are to look at history, the best thing would be using a FULL JOIN such as:
select coalesce(d.employee_id,c.employee_id) employee_id
, d.deduction_amount
, c.contribution_amount
, coalesce(d.deducation_date,c.contribution_date) check_date
from employee_deduction d
full join employee_contribution c on c.employee_id = d.employee_id
where d.DED_CD = 'H' or c.MEMO_CD = 'H'
What a FULL JOIN does is include ALL records from the first table and ALL records from the joining table regardless if there are nulls in either table.
That is why you have to use a coalesce statement in the select clause to make sure you don't wind up with a null value in the result set.
Hope this works.

access sql changing where parameters

I have a problem with a DB I'm working on, I suspect is actually a very simple problem, still I can't solve it.
For sake of brevity I will use a very simplified case.
Let's say you have a table were have been stored data about expenses made by different persons, something like this:
IDPerson Expense data
1 2.00 1/1/14
1 1.00 1/2/14
1 1.00 1/3/14
2 1.00 1/1/14
2 1.00 1/2/14
3 1.00 1/3/14
What i need is a query that gives me, for each IDPerson, the totale of expenses made before or on 1/2/14 AND the total of the expenses unregarding the date, so
IDPerson TotalExpense ExpenseBefore1/2/14
1 4.00 2.00
2 2.00 2.00
3 1.00 0.00
It seems to me that to get this you shuld have different where clauses for each column(hence the title)
What I tried:
I tried to use two queries, one without where clause and one with
Where data<=1/2/14
then I used UNION to get the final result, technically it worked, but since this it is not really handy expecially because the real project is much more complicated than this and the final table has much more fields; is there any other way to obtain this?
P.S. You may have noticed that English is not my mothertongue, sorry for any error
SELECT y.IDPerson,y.ExpensesTotal,isnull(x.ExpensesBefore_1_2_2014,0) as ExpensesBefore_1_2_2014 from
(SELECT IDPerson ,sum(expenses) as ExpensesTotal from tableA GROUP BY IDPerson) as y full join ( SELECT tableA.IDPerson , sum(expenses) as ExpensesBefore_1_2_2014 from tableA
where data < '01.02.2014'
GROUP BY tableA.IDPerson ) as x on x.IDPerson = y.IDPerson
This query should work, also it should be preaty quick if the IDPerson is Indexed or PK.
I've updated the query, try this one.
SQL Fiddle : http://sqlfiddle.com/#!3/fdaf0/1