Friends list and unread messages SQL query giving unexpected result - mysql

I have all day trying to get a result of a SQL query but does not give me the expected result.
My tables at which I consult are:
tcc_friends
id(PK AUTO_INCREMENT)
user_from (FK tcc_user (nickname) )
user_to (FK tcc_user (nickname) )
tcc_messages
id (PK AUTO_INCREMENT)
message
reg_time
wasRead
id_room (FK tcc_friends(id))
test records that have currently inserted are:
tcc_friends
id_room user_from user_to
5 hu example#gmail.com
6 hu example222222#hotmail.com
tcc_messages
id message id_room
1 a 5
2 b 5
3 c 3
SQL:
select
u.*,
f.id_room,COUNT(m.id) as newMessages
from
tcc_friends f,
tcc_user u,
tcc_messages m
where
u.nickname = 'hu' IN (u.nickname = f.user_from and f.user_to='hu') or
(u.nickname = f.user_to and f.user_from='hu') AND
(m.id_room = f.id_room and m.wasRead = 0)
GROUP BY
u.nickname;
RESULT:
id nickname id_room newMessages
81 example#gmail.com 5 2
I'm trying to get a user's friends and also add unread messages but displays only friends who have a message and I'd like to show all friends whether or not unread
Can anybody help me? Regards and Thank you all

First, don't use SELECT *. It's a horrible practice and you should get out of the habit of doing it as quickly as possible.
Second, learn how to use explicit JOINs. Don't list all of your tables in the WHERE clause. That's syntax that has been obsolete (for good reason) for 20 years. That's also what's causing your problem here because all of your joins are INNER JOINs by default.
Try something like this instead:
SELECT
U.id,
U.nickname,
F.id_room,
COUNT(M.id) as newMessages
FROM
tcc_Friends F
INNER JOIN tcc_User U ON U.nickname = F.user_from
LEFT OUTER JOIN tcc_Messages M ON
M.id_room = F.id_room AND
M.wasRead = 0 -- Are you using camelcase or underscores in column names?? Make up your mind and stick to it.
WHERE
F.user_to = 'hu'
GROUP BY
U.nickname;
That isn't going to get you all the way there, because I'm unclear on what exactly you're trying to get as far as number of unread messages - is it unread messages for the user at all? How does example#gmail.com have 2?

Remove the and m.wasRead = 0 from m.id_room = f.id_room and m.wasRead = 0 in the WHERE clause. By this query you get friends only with messages that have wasRead property 0. By doing above change you will get all the friends and 0 as the count if they don't have any new messages.

Related

Beginner SQL: JOIN clause skewing results of query

thank you all for taking the time to read and help if you can! I have a query below that is getting large and messy, I was hoping someone could point me in the right direction as I am still a beginner.
SELECT
DATE(s.created_time_stamp) AS Date,
s.security_profile_id AS Name,
COUNT(*) AS logins,
CASE
WHEN COUNT(s.security_profile_id) <= 1
THEN '1'
WHEN COUNT(s.security_profile_id) BETWEEN 2 AND 3
THEN '2-3'
ELSE '4+'
END AS sessions_summary
FROM session AS s
INNER JOIN member AS m
ON s.security_profile_id = m.security_profile_id
JOIN member_entitlement AS me ON m.id = me.member_id
JOIN member_package AS mp ON me.id = mp.member_entitlement_id
**JOIN member_channels AS mc ON mc.member_id = m.id**
where member_status = 'ACTIVE'
and metrix_exempt = 0
and m.created_time_stamp >= STR_TO_DATE('03/08/2022', '%m/%d/%Y')
and display_name not like 'john%doe%'
and email not like '%#aeturnum.com'
and email not like '%#trendertag.com'
and email not like '%#sargentlabs.com'
and member_email_status = 'ACTIVE'
and mp.package_id = 'ca972458-bc43-4822-a311-2d18bad2be96'
and display_name IS NOT NULL
and s.security_profile_id IS NOT NULL
**and mc.id IS NOT NULL**
GROUP BY
DATE(created_time_stamp),
Name
ORDER BY
DATE(created_time_stamp),
Name
The two parts of the query with asterisks are the two most recently added clauses and they skew the data. Without these, the query runs fine. I am trying get a session summary which works fine, but I only want the sessions of people who have a 'channel' created. Maybe mc.id IS NOT NULL is not the way to do this. I will share my query that shows me how many people have created channels. Essentially, I am trying to combine these two queries in the cleanest way possible. Any advice is greatly appreciated!
-- Users that have Topic Channels and Finished Set Up FOR TRIAL DASH**
select count(distinct(m.id)) AS created_topic_channel
from member m right join member_channels mc on mc.member_id = m.id
left join channels c on c.id = mc.channels_id
JOIN member_entitlement AS me ON m.id = me.member_id
JOIN member_package AS mp ON me.id = mp.member_entitlement_id
where title not like '# Mentions'
and member_status = 'ACTIVE'
and metrix_exempt = 0
and m.created_time_stamp >= STR_TO_DATE('03/08/2022', '%m/%d/%Y')
and display_name not like 'john%doe%'
and email not like '%#aeturnum.com'
and email not like '%#trendertag.com'
and email not like '%#sargentlabs.com'
and member_email_status = 'ACTIVE'
and display_name IS NOT NULL
and mp.package_id = 'ca972458-bc43-4822-a311-2d18bad2be96';
The metric I am trying to retrieve from the DB is how many users have created a channel and logged in at least twice. Thank you again and have a wonderful day!!
If id is the primary key of member_channels then it does not make sense to check if it is null.
If all you want is to check whether a member has a 'channel' created, then instead of the additional join to member_channels, which may cause the query to return more rows than expected, you could use EXISTS in the WHERE clause:
where member_status = 'ACTIVE'
and .......................
and EXISTS (SELECT 1 FROM member_channels AS mc WHERE mc.member_id = m.id)
I would guess your tables aren't at the same level of granularity. A member may have many sessions, and 0-many channels.
eg if member 123 has five sessions and creates three channels => 15 rows of data in this join.
To adjust for this, it's best practice to join on the same level of granularity. You could roll up sessions to the member level, channels to the member level, and then join both against members.

how can i find unique conversation from table in sql

I Have this table:
[Messages table]
I need to find the number of uniqe conversation -
conversation is define as senderid sent msg to reciverid, and reciverid has replied (no matter how many times or the thread length, it will be count as 1 conversation).
so if senderid = 1, reeiver id =2
and in the next row senderid = 2 and reciever id =1 this is one conversation (till the end of time)
Im really stock and not sure how to proceed.
Thanks!
You can use the functions LEAST() and GREATEST() to create unique combinations of the 2 ids and aggregate:
SELECT COUNT(DISTINCT LEAST(m1.senderid, m1.receiverid), GREATEST(m1.senderid, m1.receiverid)) counter
FROM Messages m1
WHERE EXISTS (SELECT 1 FROM Messages m2 WHERE (m2.receiverid, m2.senderid) = (m1.senderid, m1.receiverid))
See the demo.
Results (for your sample data):
counter
2
Here's one option using a self join with least and greatest to get your desired results:
select count(*)
from (
select distinct least(m1.senderid, m2.senderid), greatest(m1.receiverid, m2.receiverid)
from messages m1
join messages m2 on m1.senderid = m2.receiverid and m1.receiverid = m2.senderid
) t

write single SQLquery if possible?

There are three tables (column names are in brackets):
1-user_table (user_id, social_site)
value in social_site -> fb, whatsapp, wechat
2-booking_confirm (booking_id)
3-payment_table (order_id, payment_status)
payment_status = "success" or "fail"
no of user | social site | no of payment successful
34 | fb | 10
"no of user": find count(user_id) with respect to "fb" and "payment" (when order_id = booking_id and payment_status="success")
There's no connection between USER_TABLE (your first table) and another two tables, so the following query certainly won't work, but might give you an idea of how to do it (once you manage to fix what's wrong).
select count(*)
from user_table u join ??? on ??? --> what goes here?
--
booking_confirm b join payment_table p on b.booking_id = p.order_id
where u.social_site = 'fb'
and p.payment_status = 'success'

Error on using outer query column in subquery for date constraint

We have a Mariadb table with users details in (users)
We have a 2nd table for review dates (reviewdates)
| reviewID |USERID |A review date |
| 001 | 123 |2017-01-08 09:02:10 |
etc...
That records review meeting dates against each user.
We have a 3rd table (userdata) with multiple types of user data in. Field id 101 is new targets for the review. Field id 98 is old targets from the previous review.
|dataID|Userid |Field ID |FieldValue |UpdatedOn |UpdatedBy|
-------------------------------------------------------------
|0001 |123 | 101 |my new target|2017-01-10|145 |
|0002 |123 | 98 |my old target|2017-01-10|0 |
New Target (field ID 101) gets copied to old targets (field id 98) when the review is completed.
Either field can be updated at any time.
Each user has many review dates. I need to compare the first value of the old field after the review is complete with the last value before the review date to make sure they have copied over correctly. As users can change either field it has to a comparison of immediately before and after the completion process.
so I join users and reviewdates
select users.userid,users.username,reviewdates.meetingdate
from companyusers users
join reviewdates on reviewdates.userid = users.userid
and this gives me all the review dates for all users
I then tried to find the most recent entry for the 101 field :
select users.userid,users.username, reviewdates.meetingdate, latest101.fielddetails,latest101.updatedon
from users
join reviewdates on reviewdates.userid = users.userid
left join (select userdata.* from userdata u1
where u1.fieldid = 101
and u1.updatedOn = (select max(u2.updatedon)
from userdata u2
where u1.userid = u2.userid
and u2.fieldid = 101)
) as latest101 on (latest101.userid = users.userid)
and this works OK too but when I try to find the most recent entry before each review date:
select users.userid,users.username,reviewdates.meetingdate,latest101.fielddetails,latest101.updatedon
from users
join reviewdates on reviewdates.userid = users.userid
left join (select userdata.* from userdata u1
where u1.fieldid = 101
and u1.updatedOn = (select max(u2.updatedon)
from userdata u2
where u1.userid = u2.userid
and u2.fieldid = 101
#date limit
and u2.updatedOn < reviewdates.meetingdate)
) as latest101 on (latest101.userid = users.userid)
I get an
"unknown column reviewdates.meetingdate in where clause"
error. I've found loads of statements saying I can't refer to an outer join in a subquery but none that provide possible answers that apply to these date constraints.
Any help or pointers would be appreciated.
I do not see that you are filtering the most outer 'reveiwdates' table with anything specific, it is just used to display the 'meetingdate' based on the inner queries,
in that case firstly, there is no reason to use the same reference inside subquery.
Secondly, there are so many 'meetingdates', which specific meeting date are we comparing against the 'updatedOn' ?
You cannot join two tables on an in-equality condition.
Either a constant review date filter needs be applied or a procedure needs be written to loop through each meeting date for a user in the 'reviewdates' table.
If you just care about the latest review for that user then you could fetch and compare the latest 'reviewdate' just like how you are comparing the latest updated on, 'updatedOn' does not seem to have time component and to avoid other issues use date() or equivalent while comparing.
select users.userid,users.username,reviewdates.meetingdate,latest101.fielddetails,latest101.updatedon
from users
join reviewdates on reviewdates.userid = users.userid
left join (select userdata.* from userdata u1
where u1.fieldid = 101
and u1.updatedOn = (select max(u2.updatedon)
from userdata u2
where u1.userid = u2.userid
and u2.fieldid = 101
#date limit
and u2.updatedOn < (select date(max(reviewdates.meetingdate)) from reviewdates where u2.userid = reviewdates.userid))
) as latest101 on (latest101.userid = users.userid)

Need some support writing a MySQL-Query

I'm writing a basic message-script in PHP/MySQL but I'm stuck at a database query right now. I'll appreciate any hints or assistance (:
I'm using two tables, since a message can be sent to several users:
messages:
id | sender_id | subject | ...
message_receivers:
message_id | receiver_id | ...
What I want to do now is display a message to the user that he selects. But I want to show the whole message history the user had in that conversation (jumping in browser to the one he selected). Doing this with a join is quite simple:
SELECT * FROM messages
JOIN message_receivers
ON messages.id = message_receivers.message_id
WHERE sender_id = x
AND receiver_id = y
But now I'm missing the information of other receivers of a message! And I have no clue how to get this information. Any ideas for that? (:
Join the message_receivers table one more time to retrieve the other recipients of the message:
SELECT
m.id, m.sender_id, m.subject,
r.receiver_id AS recipient,
c.receiver_id AS carboncopy
FROM messages AS m
INNER JOIN message_receivers AS r
ON m.id = r.message_id
LEFT OUTER JOIN message_receivers AS c
ON r.message_id = c.message_id AND r.receiver_id != c.receiver_id
WHERE m.sender_id = x AND r.receiver_id = y
The recipient that your are interested in will be in column recipient (in every result record). Other recipients will be in column carboncopy (one per result record). If carboncopy is NULL, then the message had only a single receiver.
If you want to see all the receivers of a message then remove the second part of the were clause:
AND receiver_id = y
at the same time you will want to specify the message_id because this will be to confusing to the user on the front end
AND message_id = z
You're missing information about other receivers of the message because of the clasue:
AND
receiver_id = y
This restricts the result set to just receiver y. Remove the clause, and you'll get them all. However you'll probably get every message sent where sender_id = x as well, so you'll need to limit the query by specifying a message_id.
So your final query should look something like this:
SELECT
*
FROM
messages
JOIN message_receivers ON messages.id = message_receivers.message_id
WHERE
sender_id = x
AND
message_id = y
you don't need to restrict your result to receiver_id = y, do you?
Also you might write the statement in a different way and easily return receivers ids:
SELECT m.*, r.receiver_id
FROM messages m, message_receivers r
WHERE m.id = r.message_id
AND m.sender_id = x