How to get the next value from inner join SQL - mysql

This question is continue of this here, since they don't want to answer without opening new.
This is my tables:
customer_profiles
friend_levels
so I have a query that get what level he's from, so when he got points = 168 then he will getGreat Friend so this is the SQL that I've already have.
SELECT s.*
FROM customer_profiles t
INNER JOIN friend_levels s ON(t.friend_points >= s.points_needed)
WHERE s.points_needed = (SELECT max(f.points_needed)
FROM friend_levels f
WHERE t.friend_points >= f.points_needed)
AND t.user_id = $user_id
and result like this
so my question is how to get the next value of it in order to use it like this? For ex. If I am on the Great Friend level, then I have to get the Best Friend level.

This should be simple:
SELECT (SELECT min(fl.points_needed)
FROM friend_levels fl
WHERE fl.points_needed > cp.friend_points) - cp.friend_points AS points_needed_for_next_level
FROM customer_profiles cp
WHERE cp.user_id = $user_id;

Related

Working with SELECT and SUB SELECT in MySQL

I have a question about a SQL, I have never worked with the select sub and I ended up getting lost with it.
Meu SQL:
SELECT CLI.id, CLI.nome, CLI.senha, CLI.email, CLI.cpf, CLI.celular, CLI.data_nasc, CLI.genero, CLI.data_cadastro, CLI.status, CLI.id_socket, ATEN.mensagem, ARQ.nome AS foto, ATEN.data_mensagem
FROM ut_clientes AS CLI
LEFT JOIN ut_arquivos AS ARQ ON (ARQ.id_tipo = CLI.id AND ARQ.tipo = "ut_clientes")
INNER JOIN ut_atendimentos AS ATEN ON (ATEN.id_usuario_envio = CLI.id)
WHERE ATEN.id_usuario_envio != 59163
GROUP BY CLI.id
ORDER BY ATEN.data_mensagem
DESC
Well, what I would like to do is group the messages according to the customer ID and bring only the last message recorded in the database according to the data_mensagem.
I have tried in many ways but always the last one that is displayed is the first message inserted in DB.
If anyone can help me, I'll be grateful. Thank you guys!
This may help you... I am using a join to a pre-query (PQ alias). This query just goes to your messages and grabs the client ID and the most recent based on the MAX(). By doing the group by here, it will at most return 1 record per client. I also have the WHERE clause to exclude the one ID you listed.
From THAT result, you do a simple join to the rest of your query.
SELECT
CLI.id,
CLI.nome,
CLI.senha,
CLI.email,
CLI.cpf,
CLI.celular,
CLI.data_nasc,
CLI.genero,
CLI.data_cadastro,
CLI.status,
CLI.id_socket,
ATEN.mensagem,
ARQ.nome AS foto,
PQ.data_mensagem
FROM
ut_clientes AS CLI
LEFT JOIN ut_arquivos AS ARQ
ON CLI.id = ARQ.id_tipo
AND ARQ.tipo = "ut_clientes"
INNER JOIN
( select
ATEN.id_usuario_envio,
MAX( ATEN.data_mensagem ) as MostRecentMsg
from
ut_atendimentos AS ATEN
where
ATEN.id_usuario_envio != 59163
group by
ATEN.id_usuario_envio ) PQ
ON CLI.id = PQ.id_usuario_envio
GROUP BY
CLI.id
ORDER BY
PQ.data_mensagem DESC

MySQL Query limiting results by sub table

I'm really struggling with this query and I hope somebody can help.
I am querying across multiple tables to get the dataset that I require. The following query is an anonymised version:
SELECT main_table.id,
sub_table_1.field_1,
main_table.field_1,
main_table.field_2,
main_table.field_3,
main_table.field_4,
main_table.field_5,
main_table.field_6,
main_table.field_7,
sub_table_2.field_1,
sub_table_2.field_2,
sub_table_2.field_3,
sub_table_3.field_1,
sub_table_4.field_1,
sub_table_4.field_2
FROM main_table
INNER JOIN sub_table_4 ON sub_table_4.id = main_table.id
INNER JOIN sub_table_2 ON sub_table_2.id = main_table.id
INNER JOIN sub_table_3 ON sub_table_3.id = main_table.id
INNER JOIN sub_table_1 ON sub_table_1.id = main_table.id
WHERE sub_table_4.field_1 = '' AND sub_table_4.field_2 = '0' AND sub_table_2.field_1 != ''
The query works, the problem I have is sub_table_1 has a revision number (int 11). Currently I get duplicate records with different revision numbers and different versions of sub_table_1.field_1 which is to be expected, but I want to limit the result set to only include results limited by the latest revision number, giving me only the latest sub_table_1_field_1 and I really can not figure it out!
Can anybody lend me a hand?
Many Thanks.
It's always important to remember that a JOIN can be on a subquery as well as a table. You could build a subquery that returns the results you want to see then, once you've got the data you want, join it in the parent query.
It's hard to 'tailor' an answer that's specific to you problem, as it's too obfuscated (as you admit) to know what the data and tables really look like, but as an example:
Say table1 has four fields: id, revision_no, name and stuff. You want to return a distinct list of name values, with their latest version of stuff (which, we'll pretend varies by revision). You could do this in isolation as:
select t.* from table1 t
inner join
(SELECT name, max(revision_no) maxr
FROM table1
GROUP BY name) mx
on mx.name = t.name
and mx.maxr = t.revision_no;
(Note: see fiddle at the end)
That would return each individual name with the latest revision of stuff.
Once you've got that nailed down, you could then swap out
INNER JOIN sub_table_1 ON sub_table_1.id = main_table.id
....with....
INNER JOIN (select t.* from table1 t
inner join
(SELECT name, max(revision_no) maxr
FROM table1
GROUP BY name) mx
on mx.name = t.name
and mx.maxr = t.revision_no) sub_table_1
ON sub_table_1.id = main_table.id
...which would allow a join with a recordset that is more tailored to that which you want to join (again, don't get hung up on the actual query I've used, it's just there to demonstrate the method).
There may well be more elegant ways to achieve this, but it's sometimes good to start with a simple solution that's easier to replicate, then simplify it once you've got the general understanding of the what and why nailed down.
Hope that helps - as I say, it's as specific as I could offer without having an idea of the real data you're using.
(for the sake of reference, here is a fiddle with a working version of the above example query)
In your case where you only need one column from the table, make this a subquery in your select clause instead of than a join. You get the latest revision by ordering by revision number descending and limiting the result to one row.
SELECT
main_table.id,
(
select sub_table_1.field_1
from sub_table_1
where sub_table_1.id = main_table.id
order by revision_number desc
limit 1
) as sub_table_1_field_1,
main_table.field_1,
...
FROM main_table
INNER JOIN sub_table_4 ON sub_table_4.id = main_table.id
INNER JOIN sub_table_2 ON sub_table_2.id = main_table.id
INNER JOIN sub_table_3 ON sub_table_3.id = main_table.id
WHERE sub_table_4.field_1 = ''
AND sub_table_4.field_2 = '0'
AND sub_table_2.field_1 != '';

Why calling JOIN after we already found data from inner SELECT?

in the SQL statement below, why do we have to use this last JOIN on total_sellers_month?
SELECT
best.*
FROM
(SELECT
rm.rc_year,
rm.rc_month,
(SELECT vm.vd_id
FROM total_sellers_month vm
WHERE vm.rc_year = rm.rc_year AND vm.rc_month = rm.rc_month
ORDER BY rc_total DESC LIMIT 1
) AS vd_id
FROM total_months rm
) AS best
JOIN sellers v ON (v.vd_id = best.vd_id)
JOIN total_sellers_month rm
ON (rm.vd_id = best.vd_id AND rm.rc_year = best.rc_year AND rm.rc_month = best.rc_month )
ORDER BY rc_year, rc_month;
We have the second SELECT that already gives us the year, month, and id depending on the best months/years :
(SELECT
rm.rc_year,
rm.rc_month,
(SELECT vm.vd_id
FROM total_sellers_month vm
WHERE vm.rc_year = rm.rc_year AND vm.rc_month = rm.rc_month
ORDER BY rc_total DESC LIMIT 1
) AS vd_id
FROM total_months rm
) AS best
Then we add the sellers to have some more informations (the name of each seller, etc.), and the we repeat the call to total_sellers_month with a Join :
JOIN total_sellers_month rm
ON (rm.vd_id = best.vd_id AND rm.rc_year = best.rc_year AND
Why don't we just use a JOIN on "sellers"? The data we retrieved from the inner SELECT is not enough to be recognized as a table for the join?
As far as I can see you would only join from best onto total_sellers_month to get columns you did not gather from the derived table. This can be a valid technique where best is simply the way to locate the rows that you need, but then must join back to the source table for access to those complete source rows.
However as you are displaying only "select best.*" in the question there isn't a purpose to any of the joins. Perhaps this may be due to simplification for the question.

SQL query in WHERE condition

Is it good if i write query like this:- (see query in where condition)
SELECT distinct(id) "idea_id"
FROM ideas
WHERE deleted_by_user = 0 AND moderation_flag = 1 AND
user_id in (select id
from users
where confirm like "yes")
ORDER BY time_of_creation DESC
let me know if there is some issue in this query :
thanx in advance..
You can wirte this query in two ways:
SELECT DISTINCT(i.id) "idea_id"
FROM ideas i
INNER JOIN users u ON i.user_id = u.id
WHERE i.deleted_by_user = 0 AND i.moderation_flag = 1 AND u.confirm = 'yes'
ORDER BY i.time_of_creation DESC;
And
SELECT DISTINCT(i.id) "idea_id"
FROM ideas i
WHERE i.deleted_by_user = 0 AND i.moderation_flag = 1 AND
EXISTS (SELECT * FROM users u WHERE i.user_id = u.id AND u.confirm = 'yes')
ORDER BY i.time_of_creation DESC;
SELECT distinct a.ID idea_id
FROM ideas a
INNER JOIN users b
ON a.user_id = b.id
WHERE a.deleted_by_user = 0 AND
a.moderation_flag = 1
b.confirm = 'YES'
ORDER BY time_of_creation DESC
To answer your question - there are no problems with using subqueries.
On the other hand, you have (at least) three different things to think about when writing a query in one way or another:
How efficient will the data base run my query? (If the data base is small, this may not matter at all)
How easy is this to formulate and write? - which often connects to
How easy is this to understand for someone else who reads my code? (and I may myself count as "somebody else" if I look into code I've written a year ago...)
If you have a database of a size where efficiency counts, the best way to select how to formulate a query is normally to write it in different ways and test it on the data base. (but often the query optimizer in the data base is so good, it does not matter)
SELECT distinct i.id "idea_id"
FROM ideas i join users u
on i.user_id=u.id and u.confirm ='yes'
WHERE i.deleted_by_user = 0
AND i.moderation_flag = 1
ORDER BY i.time_of_creation DESC

php mysql join 3 tables

Im looping through a feedback type comment system on a users page, finding the latest 6 posts.
To display the post how I want, I have to grab data from 3 tables.
I figure it'd be less db intensive if it was all pulled in one query, but I'm not sure how to write it, being suck at JOINs and things.
This is my existing code
$sql_result = mysql_query("SELECT * FROM feedback WHERE user='1' ORDER BY date desc LIMIT 6", $db);
while($rs = mysql_fetch_array($sql_result)) {
$sql_result2 = mysql_query("SELECT * FROM members WHERE id= '$rs[author]'", $db);
$rs2 = mysql_fetch_array($sql_result2);
if ($rs2[clan] != 0) {
$sql_result3 = mysql_query("SELECT * FROM clans WHERE id= '$rs2[clan]' LIMIT 1", $db);
$rs3 = mysql_fetch_array($sql_result3);
// write comment
Can someone give me a clue?
This should do it:
select * from feedback
left join members on feedback.author = members.id
left join clans on members.clan = clans.id
where feedback.user = 1
left join means if the table on the right has no matching row, a record with all null values is returned, so you still get the data from the table on the left.
I am no expert in Sql myself, but I have picked up a few tricks here and there :-)
A typical LEFT JOIN that works in Firebird is :
select A.*,B.*,C.*
from FEEDBACK A left join MEMBERS B
on A.USER = B.ID left join CLANS C
ON C.ID = A.USER
where A.USER=1
The logic behind the join is that All rows that now share the same value,
A.USER = B.ID = C.ID will now be visible.
The letters A B and C is just used for simplicity.
F, M and C will work the same way.
This Left Join will pick out all and every column in tables. This is done with A.*,B.*,C.*
Maybe you want only a few columns in each table.
That can be accomplished by naming the columns in the same manner.
Example:
A.USER,A.FIRSTNAME,A.SURNAME,B.COLNAME1,B.COLNAME2,C.COLNAME1,C.COLNAME2
When you need to adress the columns later, remember the Prefix of A. or B. or C. before the actual column-name you address.
Good luck and best regards.
Morten, Norway