SQL Server Join tables - sql-server-2008

I want each student's name, last payment date only. means only day.

I know i won't help you at all giving this code:
But you could try to learn something from it.
SELECT S.Id, S.Name, F.max_date, F.FeeAmt
FROM tbl_student As S
INNER JOIN (
SELECT t.Id, MAX(t.Date) As max_date, t.FeeAmt FROM tbl_fees As t GROUP BY t.Id
) As F ON F.Id=S.Id
First we selected all users from tbl_student, and then we are joining fees, selecting max date and grouping by user. The result is last (date) fee per user.

Please try this query. I hope this should give you the expected output:
SELECT S.Name, T1.LastPaymentDate
FROM
(SELECT Id, Max([Date]) AS LastPaymentDate from tbl_fees GROUP BY Id) AS T1
INNER JOIN
tbl_student AS S
ON T1.Id = S.Id

SELECT S.name,SUB.LAST_DATE
FROM tbl_student S
JOIN (SELECT f.id AS ID,MAX(f.Date) AS LAST_DATE
FROM tbl_fees f
GROUP BY f.id) SUB
ON SUB.id = S.id

Related

Subquery left join refer to parent ID

I am trying to make a query to fetch the newest car for each user:
select * from users
left join
(select cars.* from cars
where cars.userid=users.userid
order by cars.year desc limit 1) as cars
on cars.userid=users.userid
It looks like it says Unknown column "users.userid" in where clause
I tried to remove cars.userid=users.userid part, but then it only fetches 1 newest car, and sticks it on to each user.
Is there any way to accomplish what I'm after? thanks!!
For this purpose, I usually use row_number():
select *
from users u left join
(select c.* , row_number() over (partition by c.userid order by c.year desc) as seqnum
from cars c
) c
on c.userid = u.userid and c.seqnum = 1;
One option is to filter the left join with a subquery:
select * -- better enumerate the columns here
from users u
left join cars c
on c.userid = u.userid
and c.year = (select max(c1.year) from cars c1 where c1.userid = c.userid)
For performance, consider an index on car(userid, year).
Note that this might return multiple cars per user if you have duplicate (userid, year) in cars. It would be better to have a real date rather than just the year.
Maybe there are better and more efficient way to query this. Here is my solution;
select users.userid, cars.*
from users
left join cars on cars.userid = users.userid
join (SELECT userid, MAX(year) AS maxDate
FROM cars
GROUP BY userid) as sub on cars.year = sub.maxDate;

Is it possible to select from the result of a subquery in a join

So I have a large subquery and I would like to join on that subquery while using the result of the subquery in the join.
For example, I have a table called patient and one called appointment, and I would like to get the number of appointments per patient with given criteria.
Right now I am doing something like this:
SELECT
t1.*
FROM
(
SELECT
patient.name,
patient.id,
appointment.date
FROM
patient
LEFT JOIN appointment ON appointment.patient_id = patient.id
WHERE
/* a **lot** of filters, additional joins, etc*/
) t1
LEFT JOIN (
SELECT
COUNT(*) number_of_appointments,
patient.id
FROM
patient
LEFT JOIN appointment ON appointment.patient_id = patient.id
GROUP BY
patient.id
) t2 ON t1.id = t2.id
The problem is that this returns the number of appointments for each patient independent from the subquery above it. I tried writing the join as this:
LEFT JOIN (
SELECT
COUNT(*) number_of_appointments,
patient.id
FROM
t1
GROUP BY
patient.id
)
But obviously I'm getting an error saying that table t1 doesn't exist. Is there any way for me to do this cleanly without having to repeat all of the filters from t1 in t2?
Thanks!
Why not use window functions?
SELECT p.name, p.id, a.date,
COUNT(a.patient_id) OVER (PARTITION BY p.id) as num_appointments
FROM patient p LEFT JOIN
appointment a
ON a.patient_id = p.id
WHERE . . .
This provides the count based on the WHERE filtering. If you wanted a count of all appointments, then do the calculation before applying the WHERE:
SELECT p.name, p.id, a.date,
COALESCE(a.cnt, 0) as num_total_appointments,
COUNT(a.patient_id) OVER (PARTITION BY p.id) as num_matching appointments
FROM patient p LEFT JOIN
(SELECT a.*,
COUNT(*) OVER (PARTITION BY a.patient_id) as cnt
FROM appointment a
) a
ON a.patient_id = p.id
WHERE . . .

Mximum hours spent by an employee on each project

I have this query
SELECT t.pname,MAX(t.name) ,MAX(t.total)
FROM
(
SELECT p.`id`,e.`name`,p.`pname`,(m.`hour`) AS total
FROM employee e INNER JOIN epmap m ON m.`employeeID`=e.`id` INNER JOIN project p ON p.`id`=m.`projectID`
)t
GROUP BY t.id
it gives the right answer, but its not the good approach beacuse Max(t.name) not appropriate
This will give you the result you need:
SELECT t.pname, t.name, t.hour as total
FROM (
SELECT p.id, e.name, p.pname, m.total,
ROW_NUMBER() OVER(partition by p.id order by m.hour desc) rn
FROM employee e
INNER JOIN epmap m ON m.employeeID=e.id
INNER JOIN project p ON p.id=m.projectID
) t
where t.rn = 1
SELECT DISTINCT would probably let you get rid of the MAX on name.

How do I join these two SQL queries?

I'm using MySQL and MSSql and I'm trying to join these two queries together.
Query 1
(SELECT REP.REP_NUM, REP.FIRST_NAME, REP.LAST_NAME
FROM REP, CUSTOMER)
Query 2
(SELECT CUSTOMER.REP_NUM, SUM(CUSTOMER.BALANCE) AS REP_BALANCE
FROM CUSTOMER
GROUP BY CUSTOMER.REP_NUM)
I've seen you can treat these as two Tables and join them but I'm having trouble getting it to work. The way I was trying to join them I'd get aggregate errors from trying to select the rep first and last name while using the balance sum.
Thanks in advance!
SELECT R.REP_NUM, R.FIRST_NAME, R.LAST_NAME
FROM REP r
inner join
(SELECT c.REP_NUM, SUM(c.BALANCE) AS REP_BALANCE
FROM CUSTOMER c
GROUP BY c.REP_NUM) t
on r.rep_num = t.rep_num
SELECT r.REP_NUM, r.FIRST_NAME, r.LAST_NAME, SUM (c.BALANCE) AS REP_BALANCE
FROM REP r
INNER JOIN CUSTOMER c ON r.REP_NUM = c.REP_NUM
GROUP BY r.REP_NUM, r.FIRST_NAME, r.LAST_NAME
try this:
SELECT REP.REP_NUM, REP.FIRST_NAME, REP.LAST_NAME
FROM REP join(
SELECT CUSTOMER.REP_NUM, SUM(CUSTOMER.BALANCE) AS REP_BALANCE
FROM CUSTOMER
GROUP BY CUSTOMER.REP_NUM
) as B on some_condition...
try it
select a.REP_NUM,a.FIRST_NAME,a.LAST_NAME,b.REP_NUM,Sum(b.BALANCE) as REP_BALANCE from REP a as inner join CUSTOMER b on a.REP_NUM=b.REP_NUM group by b.REP_NUM
Select New.REP_NUM,New.FIRST_NAME,New.LAST_NAME,CUSTOMER.REP_NUM,
SUM(CUSTOMER.BALANCE) AS REP_BALANCE
from (SELECT REP.REP_NUM, REP.FIRST_NAME, REP.LAST_NAME
FROM REP, CUSTOMER) New
inner join CUSTOMER ON CUSTOMER.REP_NUM=New.REP_NUM
GROUP BY CUSTOMER.REP_NUM

MySQL Query not displaying correctly

I am having to set up a query that retrieves the last comment made on a customer, if no one has commented on them for more than 4 weeks. I can make it work using the query below, but for some reason the comment column won't display the latest record. Instead it displays the oldest, however the date shows the newest. It may just be because I'm a noob at SQL, but what exactly am I doing wrong here?
SELECT DISTINCT
customerid, id, customername, user, MAX(date) AS 'maxdate', comment
FROM comments
WHERE customerid IN
(SELECT DISTINCT id FROM customers WHERE pastdue='1' AND hubarea='1')
AND customerid NOT IN
(SELECT DISTINCT customerid FROM comments WHERE DATEDIFF(NOW(), date) <= 27)
GROUP BY customerid
ORDER BY maxdate
The first "WHERE" clause is just ensuring that it shows only customers from a specific area, and that they are "past due enabled". The second makes sure that the customer has not been commented on within the last 27 days. It's grouped by customerid, because that is the number that is associated with each individual customer. When I get the results, everything is right except for the comment column...any ideas?
Join much better to nested query so you use the join instead of nested query
Join increase your speed
this query resolve your problem.
SELECT DISTINCT
customerid,id, customername, user, MAX(date) AS 'maxdate', comment
FROM comments inner join customers on comments.customerid = customers.id
WHERE comments.pastdue='1' AND comments.hubarea='1' AND DATEDIFF(NOW(), comments.date) <= 27
GROUP BY customerid
ORDER BY maxdate
I think this might probably do what you are trying to achieve. If you can execute it and maybe report back if it does or not, i can probably tweak it if needed. Logically, it ' should' work - IF i have understood ur problem correctly :)
SELECT X.customerid, X.maxdate, co.id, c.customername, co.user, co.comment
FROM
(SELECT customerid, MAX(date) AS 'maxdate'
FROM comments cm
INNER JOIN customers cu ON cu.id = cm.customerid
WHERE cu.pastdue='1'
AND cu.hubarea='1'
AND DATEDIFF(NOW(), cm.date) <= 27)
GROUP BY customerid) X
INNER JOIN comments co ON X.customerid = co.customerid and X.maxdate = co.date
INNER JOIN customer c ON X.customerid = c.id
ORDER BY X.maxdate
You need to have subquery for each case.
SELECT a.*
FROM comments a
INNER JOIN
(
SELECT customerID, max(`date`) maxDate
FROM comments
GROUP BY customerID
) b ON a.customerID = b.customerID AND
a.`date` = b.maxDate
INNER JOIN
(
SELECT DISTINCT ID
FROM customers
WHERE pastdue = 1 AND hubarea = 1
) c ON c.ID = a.customerID
LEFT JOIN
(
SELECT DISTINCT customerid
FROM comments
WHERE DATEDIFF(NOW(), date) <= 27
) d ON a.customerID = d.customerID
WHERE d.customerID IS NULL
The first join gets the latest record for each customer.
The second join shows only customers from a specific area, and that they are "past due enabled".
The third join, which uses LEFT JOIN, select all customers that has not been commented on within the last 27 days. In this case,only records without on the list are selected because of the condition d.customerID IS NULL.
But tomake your query shorter, if the customers table has already unique records for customer, then you don't need to have subquery on it.Directly join the table and put the condition on the WHERE clause.
SELECT a.*
FROM comments a
INNER JOIN
(
SELECT customerID, max(`date`) maxDate
FROM comments
GROUP BY customerID
) b ON a.customerID = b.customerID AND
a.`date` = b.maxDate
INNER JOIN customers c
ON c.ID = a.customerID
LEFT JOIN
(
SELECT DISTINCT customerid
FROM comments
WHERE DATEDIFF(NOW(), date) <= 27
) d ON a.customerID = d.customerID
WHERE d.customerID IS NULL AND
c.pastdue = 1 AND
c.hubarea = 1
Two of your table columns are not contained in either an aggregate function or the GROUP BY clause. for example suppose that you have two data rows with the same customer id and same date, but with different comment data. how SQL should aggregate these two rows? :( it will generate an error...
try this
select customerid, id, customername, user,date, comment from(
select customerid, id, customername, user,date, comment,
#rank := IF(#current_customer = id, #rank+ 1, 1),
#current_customer := id
from comments
where customerid IN
(SELECT DISTINCT id FROM customers WHERE pastdue='1' AND hubarea='1')
AND customerid NOT IN
(SELECT DISTINCT customerid FROM comments WHERE DATEDIFF(NOW(), date) <= 27)
order by customerid, maxdate desc
) where rank <= 1