I have 2 tables which I want to join and retrieve some specific data. These are my tables.
tbl_user (reg_id, l_name, f_name, status)
tbl_payments (pay_id, reg_id, mem_plan, from_date, to_date, bill_no, payed_date)
What I need to do is select and view the users who have due payments. To do that I want to get the user details where "status=0" from tbl_user and join the 2 tables together and the conditions are to_date< current date, difference between [current date and the to_date] < 31 and filter by the Max value of to_date.
What I did so far gives me a result according to above mentioned conditions except it dosen't filter by the MAX(to_date). This is my query.
SELECT
A.reg_id,
A.f_name,
A.l_name,
B.mem_plan,
B.from_date,
Max(B.to_date) AS to_date,
B.bill_no,
B.payed_date
FROM
tbl_user A,
tbl_payments B
WHERE
A.status = 0
AND A.reg_id = B.reg_id
AND Date(Now()) >= Date(B.to_date)
AND Datediff(Date(Now()), Date(b.to_date)) < 31
GROUP BY
a.reg_id, b.mem_plan, b.from_date, b.bill_no, b.payed_date;
I'm not very familiar with MYSQL, So please someone tell me what I did wrong or if this query is not up to the standard.
Here are some sample data to work on.
tbl_user ( [M1111,Jon, Doe,0], [M1112,Jane,Doe,1],[M1113,Jony,Doe,0] )
tbl_payment ( [1,M1111,Monthly,2018-05-14,2018-06-14,b123,2018-05-14],[2,M1112,3Months,2018-02-03,2018-05-03,b112,2018-02-03],[3,M1113,Monthly,2018-06-14,2018-07-14,b158,2018-06-14],[4,M1111,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[5,M1113,Monthly,2018-06-06,2018-07-06,b158,2018-06-06],[6,M1111,Monthly,2018-07-05,2018-08-05,b345,2018-07-05] )
Assuming current date is 2018-07-17, The expecting result should be this
[M1111,Jon,Doe,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[M1113,Jony,Doe,Monthly,2018-06-14,2018-07-14,b158,2018-06-14]
Instead of that, my query gives me this.
[M1111,Jon,Doe,Monthly,2018-06-15,2018-07-15,b345,2018-06-15],[M1113,Jony,Doe,Monthly,2018-06-06,2018-07-06,b158,2018-06-06],
[M1113,Jony,Doe,Monthly,2018-06-14,2018-07-14,b158,2018-06-14]
I wrote another query which gives me the result set exactly as i want. But I'm not sure whether it's up to the standards. If someone can simplify this or make it better, appreciate very much.
SELECT A.reg_id,A.f_name,A.l_name,D.mem_plan,D.from_date,D.to_date,D.bill_no,D.payed_date
FROM tbl_user A
JOIN (SELECT B.reg_id,B.mem_plan,B.from_date,B.to_date,B.bill_no,B.payed_date
FROM tbl_payments B
JOIN (
SELECT reg_id, MAX(to_date) as to_date
FROM tbl_payments
WHERE DATE(NOW()) >= DATE(to_date) AND DATEDIFF(DATE(NOW()), DATE(to_date))<31
GROUP BY reg_id) C
ON B.reg_id = C.reg_id AND B.to_date= C.to_date) D
ON A.reg_id = D.reg_id
WHERE A.status=0;
I believe having won't work here and that your second query is about as good as it gets. I've condensed it a little here:
SELECT A.reg_id,f_name,l_name,mem_plan,from_date,to_date,bill_no,payed_date
FROM #tbl_user A
JOIN #tbl_payments B ON A.reg_id = b.reg_id
JOIN (
SELECT reg_id, MAX(to_date) as max_to_date
FROM #tbl_payments
WHERE DATE(NOW()) >= DATE(to_date) AND DATEDIFF(DATE(NOW()), DATE(to_date))<31
GROUP BY reg_id
) C ON B.reg_id = C.reg_id AND B.to_date= C.max_to_date
WHERE A.status=0;
I am trying to build the SQL query from following table (example):
Example of table with name "performances"
This is table with athletic performances. I want to select the best perform from this table per discipline and set of one or more categories. Each athlete should be only once in result though his best perform value is twice or more in performance table.
Here is expected result from table "performances"
Actually I have this SQL query, but from subquery join all rows with best value for athlete_id and best:
SELECT
p.athlete_id, p.value
FROM
(SELECT athlete_id, MAX(value) AS best FROM performances
WHERE discipline_id = 32 AND category_id IN (1,3,5,7,9)
GROUP BY athlete_id) f
INNER JOIN performances p
ON p.athlete_id = f.athlete_id AND p.conversion = f.best
ORDER BY p.value DESC, p.created
Please, how can I join only one row for each athlete, which has a oldest created attributte?
To get the single row for each athlete per discipline based on greatest value value you can do a self left join, To handle the tie case or if single athlete has more than 1 rows having same maximum value you can use case statement to pick the row with oldest date
select a.*
from performances a
left join performances b
on a.discipline_id = b.discipline_id
and a.athlete_id = b.athlete_id
and case when a.value = b.value
then a.created > b.created
else a.value < b.value
end
where b.discipline_id is null
DEMO
Further you can add filter in your where clause
and a.discipline_id = 32
and a.category_id IN (1,3,5,7,9)
DEMO
You don't have to use joins, you can do it with a window function:
SELECT
p.athlete_id,
p.value
FROM
(
SELECT
athlete_id,
value,
ROW_NUMBER() over (partition by athlete_id order by value desc, created) rowid
FROM
performances
WHERE
discipline_id = 32 AND
category_id IN (1,3,5,7,9)
) p
where
p.rowid = 1
Thank you a lot, Guys. After your answers I finally found the solution.
SELECT r.* FROM
(SELECT p.athlete_id, p.conversion, MIN(p.created) AS created FROM
(SELECT athlete_id, MAX(conversion) AS best
FROM performances
WHERE discipline_id = 32 AND category_id IN (1,3,5,7,9)
GROUP BY athlete_id) f
INNER JOIN performances p ON p.athlete_id = f.athlete_id AND p.conversion = f.best
GROUP BY p.athlete_id) w INNER JOIN performances r
ON w.athlete_id = r.athlete_id AND w.conversion = r.conversion
AND ((w.created = r.created) OR (w.created IS NULL AND r.created IS NULL))
ORDER BY r.conversion DESC, r.created
I'm having an issue updating a table with a select using multiple joins. I feel like everything is in place but I'm getting some syntax problems around the end, as commented below.
UPDATE ambition.ambition_totals a
INNER JOIN (SELECT
c.user AS UserID,
COUNT(*) AS dealers,
ROUND((al.NumberOfDealers / al.NumberOfDealerContacts) * 100 ,2) AS percent
FROM contact_events c
JOIN users u
ON c.user = u.id
JOIN dealers d
ON c.dealer_num = d.dealer_num
LEFT JOIN (
SELECT user_id, COUNT(*) AS NumberOfDealerContacts,
SUM(CASE WHEN ( d.next_call_date + INTERVAL 7 DAY) THEN 1 ELSE 0 END) AS NumberOfDealers
FROM attr_list AS al
JOIN dealers AS d ON d.csr = al.data
WHERE al.attr_id = 14
GROUP BY user_id)) as al
ON al.user_id = a.ext_id -- this is where I have a syntax error
SET a.dealers_contacted = al.dealers,
a.percent_up_to_date = al.percent;
As shown, I'm getting the data needed from these joins but I'm unable to update based on my ON clause in the final join. The select itself works apart from this, but I'm just trying to alter it to update a table.
I'm sure I'm just overlooking something in the syntax but I get an error that 'every derived table must have its own alias'.
UPDATE
Original working select that needs to be converted into the update:
SELECT
c.user AS UserID,
COUNT(*) AS Number_of_recorded_events,
ROUND((al.NumberOfDealers / al.NumberOfDealerContacts) * 100 ,2) AS Percentage_up_to_date
FROM contact_events c
JOIN users u
ON c.user = u.id
JOIN dealers d
ON c.dealer_num = d.dealer_num
LEFT JOIN (
SELECT user_id, COUNT(*) AS NumberOfDealerContacts,
SUM(CASE WHEN ( d.next_call_date + INTERVAL 7 DAY) THEN 1 ELSE 0 END) AS NumberOfDealers
FROM jackson_id.attr_list AS al
JOIN jfi_dealers.dealers AS d ON d.csr = al.data
WHERE al.attr_id = 14
GROUP BY user_id) AS al
ON al.user_id = c.user
GROUP BY UserID;
'every derived table must have its own alias'
This error is pretty clear. A derived table is when you put a subquery in a FROM clause or JOIN clause, which you do twice in your query.
Every time you do this, you must give each of these derived table subqueries an alias, so you can reference columns returned by the subquery.
Like:
SELECT t.foo FROM (SELECT foo FROM MyTable) AS t
This must be done for every such subquery. In your case, you have something like this form:
UPDATE a
INNER JOIN (
SELECT ... FROM c JOIN u JOIN d
LEFT JOIN (SELECT ... FROM al JOIN d ...)
) AS al
SET ...
You have one level of subquery, which you give the alias al.
But you don't give an alias for the innermost subquery, the one you did a LEFT JOIN on. That one needs an alias too.
P.S.: This question is actually a duplicate of What is the error "Every derived table must have its own alias" in MySQL? from 2009. I know Stack Overflow encourages us to close new questions as duplicates if there is already an old answer. But I also know the reality is that people tend not to search old posts much.
On the other hand, that old Stack Overflow post from 2009 is literally the first result when I google for the error string 'every derived table must have its own alias'.
there's select which i'm trying to make work
SELECT DISTINCT a.client_key, client_name
FROM Bloggers AS a
LEFT JOIN BloggersPosts AS b
ON a.client_key = b.client_key
WHERE a.status = 1 AND
0 NOT IN (SELECT MIN(STATUS) FROM BloggersPosts AS c WHERE c.client_key=a.client_key)
For some reason 0 NOT IN (SELECT MIN(STATUS) FROM BloggersPosts AS c WHERE c.client_key=a.client_key) is not working, any ideas how to make it work?
EDIT: by not working i mean that if i delete the susbelect - my query gives result rows. But as soon as I add it - there is empty result. At the same time when i execute the subselect alone SELECT MIN(STATUS) FROM BloggersPosts - it returns 1, which means that putting it as subselect - should return results too, but it doesn't.
Thank you
I hope this will do your job. Trying different solution for your problem.
SELECT DISTINCT a.client_key, client_name
FROM Bloggers AS a
JOIN (SELECT client_key, MIN(STATUS) minstatus FROM BloggersPosts GROUP BY client_key) b
ON a.client_key = b.client_key AND minstatus <> 0
WHERE a.status = 1
Use JOIN instead, something like similar:
SELECT DISTINCT a.client_key, client_name, MIN(c.STATUS) blog_status
FROM Bloggers AS a
LEFT JOIN BloggersPosts AS b ON a.client_key = b.client_key
LEFT JOIN BloggersPosts AS c ON c.client_key = a.client_key
WHERE a.status = 1
HAVING blog_status <> 0
I have written an sql statement that besides all the other columns should return the number of comments and the number of likes of a certain post. It works perfectly when I don't try to get the number of times it has been shared too. When I try to get the number of time it was shared instead it returns a wrong number of like that seems to be either the number of shares and likes or something like that. Here is the code:
SELECT
[...],
count(CS.commentId) as shares,
count(CL.commentId) as numberOfLikes
FROM
(SELECT *
FROM accountSpecifics
WHERE institutionId= '{$keyword['id']}') `AS`
INNER JOIN
account A ON A.id = `AS`.accountId
INNER JOIN
comment C ON C.accountId = A.id
LEFT JOIN
commentLikes CL ON C.commentId = CL.commentId
LEFT JOIN
commentShares CS ON C.commentId = CS.commentId
GROUP BY
C.time
ORDER BY
year, month, hour, month
Could you also tell me if you think this is an efficient SQL statement or if you would do it differently? thank you!
Do this instead:
SELECT
[...],
(select count(*) from commentLikes CL where C.commentId = CL.commentId) as shares,
(select count(*) from commentShares CS where C.commentId = CS.commentId) as numberOfLikes
FROM
(SELECT *
FROM accountSpecifics
WHERE institutionId= '{$keyword['id']}') `AS`
INNER JOIN account A ON A.id = `AS`.accountId
INNER JOIN comment C ON C.accountId = A.id
GROUP BY C.time
ORDER BY year, month, hour, month
If you use JOINs, you're getting back one result set, and COUNT(any field) simply counts the rows and will always compute the same thing, and in this case the wrong thing. Subqueries are what you need here. Good luck!
EDIT: as posted below, count(distinct something) can also work, but it's making the database do more work than necessary for the answer you want to end up with.
Quick fix:
SELECT
[...],
count(DISTINCT CS.commentId) as shares,
count(DISTINCT CL.commentId) as numberOfLikes
Better approach:
SELECT [...]
, Coalesce(shares.numberOfShares, 0) As numberOfShares
, Coalesce(likes.numberOfLikes , 0) As numberOfLikes
FROM [...]
LEFT
JOIN (
SELECT commentId
, Count(*) As numberOfShares
FROM commentShares
GROUP
BY commentId
) As shares
ON shares.commentId = c.commentId
LEFT
JOIN (
SELECT commentId
, Count(*) As numberOfLikes
FROM commentLikes
GROUP
BY commentId
) As likes
ON likes.commentId = c.commentId