Greater Than and Less Than Equal to in SQL Server inner join NEED - sql-server-2012

I am currently developing a system that allows you to loan money. The thing is in order to place a loan you must pass the required or must have greater amount in your deposit in your bank acct.
Here is the schema for the deposit
tbl_fxd_dep:
fxid | amount
1 10,000
2 15,000.01
3 20,000.01
Here is the schema for the employees amount deposited
tbl_employee:
empid | amount
1 15,100.01
as you can see there the amount of the employees deposit is neither equal to 15,000.01 and 20,000.01 but rather in between those amounts
Here is my sql statement
Select
empid, fname, mname, lname, st, prv, city, cnt, fxid
from
emp as e
inner join
fd as f on e.amount >= f.amount
and e.amount <= f.amount
where
uname = #user and pwd = #pwd
This is an inner join statement that I created the problem is that whenever I try to log in using the users acct and password it does not query the profile of the user I tried removing this part and e.amount <= f.amount the fxid that is pulls up is 1 rather than showing the fxid it should belong to in this case 2 by can somebody provide me a alternative solution to this problem
THANK YOU and appreciate any effort that you guys give...

You have a pretty severe logical flaw in your join criteria - namely, since only one row is being considered at any given time, the only value that can be both less than or equal to x and greater than or equal to x is by definition equal to x. That's what marc_s is trying to point out in the comments: the criteria you're using isn't doing what you think it is. You can run through this pretty quickly, since you have a small data set: just substitute the literal value 15000.01 for e.amount and look at the data.
What you appear to want is to get the highest fxid that a given employee qualifies for (side note: why employee and not customer?). You can do that with a query like the following:
SELECT
empid
,fxid = MAX(fxid)
FROM
emp AS e
INNER JOIN fd AS f
ON e.amount <= f.amount
WHERE
uname = #user AND
pwd = #pwd
GROUP BY
empid
SQL Server is going to take this query and
Select the data for the employee
Connect that data to all values it is eligible for (deposit limit is less than the deposit amount)
Aggregate the data so it only returns one row for the employee, and the biggest fxid that the employee qualifies for.

Related

SQL - request to find the average loans by user

I am struggling with a SQL request.
I need to find a request to calculate the average loans per user.
I was thinking in doing a LEFT OUTER JOIN between the table SUSCRIBER and the table Loan in order to get all the subscribers even if they have made a loan or not.
Then I have used a GROUP BY based on the IDNumber of the suscribers to COUNT the number of lines. Then I need to get the total numbers of suscribers to calculate the average but by doing this I get 1 or 0 only instead of an average. I don't know what is wrong in this request. Maybe as I have made a group by the IDNumber from the table Loan. How could I get the number of all IDNumber based on this request to make the division ? Thanks
See, the request written in English:
SELECT COUNT(Loan.IDNumber) / COUNT(SUSCRIBER.IDNumber), SUSCRIBER.Name AS Name
FROM SUSCRIBER
LEFT OUTER JOIN Loan
ON SUSCRIBER.IDNumber = Loan.IDNumber
GROUP BY Loan.IDNumber;
Here are the tables:
TOPIC(Code_topic, Description)
KEY_WORD(Code_key_word, keyword)
PUBLISHER(Code_publisher, Name, Adress)
AUTHOR(Code_author, Name, Surname)
BOOK(Code_catalogue, Title, #Code_topic)
COPY (Code_bookshelf, Code_wear, Date_aquisition, #Code_publisher, #Code_catalogue)
SUSCRIBER(IDNumber, Name, Adress, Phone, Birthdate, Subscription_date)
Loan(#IDNumber,Code_bookshelf,Loan_date, Return_date)
Thank you in advance
I need to find a request to calculate the average loans per user.
If you want the average number of loans per subscriber, then you want the total number of loans divided by the number of subscribers. You can do this with an expression like this:
SELECT num_l * 1.0 / num_s
FROM (SELECT COUNT(*) as num_s FROM SUBCRIBER) s CROSS JOIN
(SELECT COUNT(*) as num_l FROM Loan) l;
The * 1.0 is because some databases do integer division, so 3 / 2 = 1 rather than 1.5.

SQL joining two tables with different levels of details

So I have two tables of sales, budget and actual.
"budget" has two columns: location and sales. For example,
location sales
24 $20000
36 $100300
40 $24700
Total $145000
"actual" has three columns: invoice_number, location, and sales. For example,
invoice location sales
10000 36 $5000
10001 40 $6000
10002 99 $7000
and so forth
Total $110000
In summary, "actual" records transactions at the invoice level, whereas "budget" is done at the location level only (no individual invoices).
I'm trying to create a summary table that lists actual and budget sales side by side, grouped by location. The total of the actual column should be $110000, and $145000 for budget. This is my attempt at it (on pgAdmin/ postgresql):
SELECT actual.location, SUM(actual.sales) AS actual_sales, SUM(budget.sales) AS budget_sales
FROM actual LEFT JOIN budget
ON actual.location = budget.location
GROUP BY actual.location;
I used LEFT JOIN because "actual" has locations that "budget" doesn't have (e.g. location 99).
I ended up with some gigantic numbers ($millions) on both the actual_sales and budget_sales columns, far exceeding the total actual ($110000) or budget sales ($145,000).
Is this because the way I wrote my query is basically asking SQL to join each invoice in "actual" to each line in "budget," therefore duplicating things many times over? If so how should I have written this?
Thanks in advance!
Based on your description, you seem to have duplicates in both tables. There are various ways to solve this problem. Here is one using union all and group by:
select Location,
sum(actual_sales) as actual_sales,
sum(budget_sales) as budget_sales
from ((select a.location, a.sales as actual_sales, null as budget_sales
from actual a
) union all
(select b.location, null, b.sales
from budget b
)
) ab
group by location;
This structure guarantees that each value is counted only once, regardless of the table.
The query looks fine to me. However, it is difficult to find out why the figures are wrong. My suggestion is that you do the sum by location separately for budget and actual into 2 temporary tables, and later put them together using LEFT JOIN.
Yes, you're joining the budget in once for each actual sales row. However, your Actual Sales sum shouldn't have been larger unless there were multiple budget rows for the same location. You should check for that, because it doesn't sound like there should be.
What you need to do in a case like this is sum the actual sales first in a CTE or subquery, then later join the result to the budget. That way you only have one row for each location. This does it for the actual sales. If you really do have more than one row for a location for budget as well, you might need to subquery the budget as well the same way.
Select Act.Location, Act.actual_sales, budget.sales as budget_sales
From
(
SELECT actual.location, SUM(actual.sales) AS actual_sales
FROM actual
GROUP BY actual.location
) Act
left join budget on Act.location = budget.location
Gordon's suggestion is good, an alternative using WITH statements is:
WITH aloc AS (
SELECT location, SUM(sales) FROM actual GROUP BY 1
), bloc AS (
SELECT location, SUM(sales) FROM budget GROUP BY 1
)
SELECT location, a.sum AS actual_sales, b.sum AS budget_sales
FROM aloc a LEFT JOIN bloc b USING (location)
This is equivalent to:
SELECT location, a.sum AS actual_sales, b.sum AS budget_sales
FROM (SELECT location, SUM(sales) FROM actual GROUP BY 1) a LEFT JOIN
(SELECT location, SUM(sales) FROM budget GROUP BY 1) b USING (location)
but I find WITH statements more readable.
The purpose of the subqueries is to get tables into a state where a row means something relevant, i.e. aloc contains a row per location, and hence cause the join to evaluate to what you want.

Joining Tables to Get Sums - SQL/Access

I am create an Access database at work for our call center. Right now there are four tables:
MASTERTABLE: DisplayName, CLOCKid (PrimaryKey), PHONEid
ROSTERTABLE: CLOCKid (ForeignKey), StartDate, EndDate
PHONELOG: PHONEid, DateStamp, StatusHours
TIMECLOCK: CLOCKid, DateStamp, HoursByDay
The Mastertable has one row for each unique employee. It contains each employee's various IDs/usernames for things listed above and other items. The Rostertable contains a row for each employee's position--an employee can have multiple positions over time, indicated by StartDate and EndDate, thus multiple rows. This is so we keep a historical record we can query. The PhoneLog is fed in from our phone system. It has multiple lines per user, representing each phone status the the amount of time the user spent in the status. The TimeClock is similar; An employee will have one row per day worked.
I need to create a query in Microsoft Access 2013, preferably using SQL, that will give me the Sum of everyone's TimeClock hours within their rostertable start/end times as well as the same for their phone hours. So the resulting query will list each employee from the RosterTable, the sum of their phone time, and the sum of their paid time.
Hope this makes sense. Let me know if anyone has questions/need clarification.
SELECT MT.DisplayName, Sum(PL.StatusHours) as PhoneHours, Sum(TC.HoursByDay) as PaidTime
FROM MASTERTABLE MT
INNER JOIN ROSTERTABLE RT
ON MT.ClockID = RT.ClockID
LEFT JOIN PHONELOG PL
ON MT.PhoneID = PL.PhoneID
LEFT JOIN TIMECLOCK TC
ON MT.ClockID = TC.ClockID
WHERE RT.StartDate >= YourStartDate
AND RT.EndDate =< YourEndDate
You just have to define YourStartDate and YourEndDate, which could be text boxes on a form or input boxes in a query, or even inner joined from another table.

SQL Output Question

Edited
I am running into an error and I know what is happening but I can't see what is causing it. Below is the sql code I am using. Basically I am getting the general results I want, however I am not accurately giving the query the correct 'where' clause.
If this is of any assistance. The count is coming out as this:
Total Tier
1 High
2 Low
There are 4 records in the Enrollment table. 3 are active, and 1 is not. Only 2 of the records should be displayed. 1 for High, and 1 for low. The second Low record that is in the total was flagged as 'inactive' on 12/30/2010 and reflagged again on 1/12/2011 so it should not be in the results. I changed the initial '<=' to '=' and the results stayed the same.
I need to exclude any record from Enrollments_Status_Change that where the "active_status" was changed to 0 before the date.
SELECT COUNT(dbo.Enrollments.Customer_ID) AS Total,
dbo.Phone_Tier.Tier
FROM dbo.Phone_Tier as p
JOIN dbo.Enrollments as eON p.Phone_Model = e.Phone_Model
WHERE (e.Customer_ID NOT IN
(Select Customer_ID
From dbo.Enrollment_Status_Change as Status
Where (Change_Date >'12/31/2010')))
GROUP BY dbo.Phone_Tier.Tier
Thanks for any assistance and I apologize for any confusion. This is my first time here and i'm trying to correct my etiquette on the fly.
If you don't want any of the fields from that table dbo.Enrollment_Status_Change, and you don't seem to use it in any way — why even include it in the JOINs? Just leave it out.
Plus: start using table aliases. This is very hard to read if you use the full table name in each JOIN condition and WHERE clause.
Your code should be:
SELECT
COUNT(e.Customer_ID) AS Total, p.Tier
FROM
dbo.Phone_Tier p
INNER JOIN
dbo.Enrollments e ON p.Phone_Model = e.Phone_Model
WHERE
e.Active_Status = 1
AND EXISTS (SELECT DISTINCT Customer_ID
FROM dbo.Enrollment_Status_Change AS Status
WHERE (Change_Date <= '12/31/2010'))
GROUP BY
p.Tier
Also: most likely, your EXISTS check is wrong — since you didn't post your table structures, I can only guess — but my guess would be:
AND EXISTS (SELECT * FROM dbo.Enrollment_Status_Change
WHERE Change_Date <= '12/31/2010' AND CustomerID = e.CustomerID)
Check for existence of any entries in dbo.Enrollment_Status_Change for the customer defined by e.CustomerID, with a Change_Date before that cut-off date. Right?
Assuming you want to:
exclude all customers whose latest enrollment_status_change record was since the start of 2011
but
include all customers whose latest enrollment_status_change record was earlier than the end of 2010 (why else would you have put that EXISTS clause in?)
Then this should do it:
SELECT COUNT(e.Customer_ID) AS Total,
p.Tier
FROM dbo.Phone_Tier p
JOIN dbo.Enrollments e ON p.Phone_Model = e.Phone_Model
WHERE dbo.Enrollments.Active_Status = 1
AND e.Customer_ID NOT IN (
SELECT Customer_ID
FROM dbo.Enrollment_Status_Change status
WHERE (Change_Date >= '2011-01-01')
)
GROUP BY p.Tier
Basically, the problem with your code is that joining a one-to-many table will always increase the row count. If you wanted to exclude all the records that had a matching row in the other table this would be fine -- you could just use a LEFT JOIN and then set a WHERE clause like Customer_ID IS NULL.
But because you want to exclude a subset of the enrollment_status_change table, you must use a subquery.
Your intention is not clear from the example given, but if you wanted to exclude anyone who's enrollment_status_change as before 2011, but include those who's status change was since 2011, you'd just swap the date comparator for <.
Is this any help?

Finding drop off rate from membership table in SQL Server 2005

We have a view that stores the history of membership plans held by our members and we have been running a half price direct debit offer for some time. We've been asked to report on whether people are allowing the direct debit to renew (at full price) but I'm no SQL expert!
The view in effect is
memberRef, historyRef, validFrom, validTo,MembershipType,PaymentType,totalAmount
Here
memberRef identifies the person (int)
historyRef identifies this row (int)
validFrom and validTo are the start and end of the plan (datetime)
MembershipType is the type of plan (int)
PaymentType is direct debit or credit card (a string - DD or EFT)
totalAmount is the price of the plan (decimal)
I'm wondering if there is a query as opposed to a cursor I can use to count the number of policies which are at half price and have another direct debit policy that follows on from it.
If we can also capture if that person first joined at half price or if there was a gap where membership had lapsed before they took the half price incentive that would be great.
Thanks in advance for any help!
For example
select count(MemberRef), max(vhOuter.validFrom) "most recent plan start",
(select top(1) vh2.validFrom
from v_Membershiphistory vh2
where (vh2.totalamount = 14.97 or vh2.totalamount = 25.50)
and vh2.memberref = vhOuter.memberref
order by createdat desc
) "half price plan start"
from v_membershiphistory vhOuter
where vhOuter.memberref in (select vh1.memberref from v_membershiphistory vh1 where vh1.totalamount = 14.97 or vh1.totalamount = 25.50)--have taken up offer
group by memberref
having max(vhOuter.validFrom) > (select top(1) vh2.validFrom
from v_Membershiphistory vh2
where (vh2.totalamount = 14.97 or vh2.totalamount = 25.50)
and vh2.memberref = vhOuter.memberref
order by createdat desc
)
This will display the members who have a half price plan and have a valid from date that is greater than the valid from date of that plan.
Not quite right as we should be testing that it is the same plan but...
if I change the select here to just count(memberRef) I get the count of memberRef for the member I'm grouping for each member I'm grouping i.e. for 5220 results I'd get 5220 rows returned each with in effect the number of plans I've selected
But I need to count the number of people taking the offer and proportion that renew. Also that renewal rate in the population that aren't taking the offer (which I'm guessing is a trivial change once I've got one set sorted)
I suppose I'm looking at how one operates on the set but compares multiple rows for each distinct person without using a cursor. But I might be wrong :)
try something like:
SELECT
a.*, b.*
FROM YourTable a
INNER JOIN YourTable b On a.memberRef=b.memberRef and a.validToDate<b.validFromDate
WHERE b.PaymentType='?direct debit?' and a.Cost='?half price?'
to get just counts use something like:
SELECT
COUNT(a.memberRef) AS TotalCount
FROM YourTable a
INNER JOIN YourTable b On a.memberRef=b.memberRef and a.validToDate<b.validFromDate
WHERE b.PaymentType='?direct debit?' and a.Cost='?half price?'