Trying to create an sql subquery - mysql

I'm new to mysql and am trying to write a subquery where I find the player and their phonenumber with the earliest creation date. I'm stuck with getting the subquery to work as the error 'Invalid use of group function' keeps displaying. What am I doing wrong?
SELECT username, phoneNumber
FROM phonenumber
WHERE username = (SELECT username
FROM player
WHERE MIN(creationDateTime));

if you want to use subquery then get user with min creation date. Then use this user name to get phone number. you can use below query. I am assuming that that will be only one user with min creation date as mentioned by you.
SELECT username, phoneNumber
FROM phonenumber
where username =
(
select username from player
where creationDateTime =
(
SELECT min(creationDateTime) from player
)
)
There are other better option than subquery.

SELECT PN.username, PN.phoneNumber, PL.min_creationDateTime FROM phonenumber AS PN
LEFT JOIN (SELECT username, MIN(creationDateTime) AS min_creationDateTime FROM player GROUP BY username) AS PL
ON PN.username = A.username
It should give you the result you're looking for.

If you want one player, I would suggest order by and limit:
SELECT pn.username, pn.phoneNumber
FROM phonenumber pn
WHERE pn.username = (SELECT p.username
FROM player p
ORDER BY creationDateTime
LIMIT 1
);

Related

SQL query with most recent name and total count

I already have a table, "table_one", set up on phpMyAdmin that has the following columns:
USER_ID: A discord user ID (message.author.id)
USER_NAME: A discord username (message.author.name)
USER_NICKNAME: The user's display name on the server (message.author.display_name)
TIMESTAMP: A datetime timestamp when the message was entered (message.created_at)
MESSAGE CONTENT: A cleaned input keyword to successful completion of content, just for this example consider "apple" or "orange" as the two target keywords.
What I'd like as a result is a view or query that returns a table with the following:
The user's most recent display name (USER_NICKNAME), based off the most recent timestamp
The total number of times a user has entered a specific keyword. Such as confining the search to only include "apple" but not instances "orange"
My intention is that if a user entered a keyword 10 times, then changed their server nickname and entered the same keyword 10 more times, the result would show their most recent nickname and that they entered the keyword 20 times in total.
This is the closest I have gotten to my desired result so far. The query correctly groups instances where user has changed their nickname based on the static discord ID, but I would like it to retain this functionality while instead showing the most recent USER_NICKNAME instead of a USER_ID:
SELECT USER_ID, COUNT(USER_ID)
FROM table_one
WHERE MESSAGE_CONTENT = 'apple'
GROUP BY USER_ID
I don't think there is an uncomplicated way to do this. In Postgres, I would use the SELECT DISTINCT ON to get the nickname, but in MySQL I believe you are limited to JOINing grouped queries.
I would combine two queries (or three, depending how you look at it).
First, to get the keyword count, use your original query:
SELECT USER_ID, COUNT(USER_ID) as apple_count
FROM table_one
WHERE MESSAGE_CONTENT = 'apple'
GROUP BY USER_ID;
Second, to get the last nickname, group by USER_ID without subsetting rows and use the result as a subquery in a JOIN statement:
SELECT a.USER_ID, a.USER_NICKNAME AS last_nickname
FROM table_one a
INNER JOIN
(SELECT USER_ID, MAX(TIMESTAMP) AS max_ts
FROM table_one
GROUP BY USER_ID) b
ON a.USER_ID = b.USER_ID AND TIMESTAMP = max_ts
I would then JOIN these two, using a WITH statement to increase the clarity of what's going on:
WITH
nicknames AS
(SELECT a.USER_ID, a.USER_NICKNAME AS last_nickname
FROM table_one a
INNER JOIN
(SELECT USER_ID, MAX(TIMESTAMP) AS max_ts
FROM table_one
GROUP BY USER_ID) b
ON a.USER_ID = b.USER_ID AND TIMESTAMP = max_ts),
counts AS
(SELECT USER_ID, COUNT(USER_ID) AS apple_count
FROM table_one
WHERE MESSAGE_CONTENT = 'apple'
GROUP BY USER_ID)
SELECT nicknames.USER_ID, nicknames.last_nickname, counts.apple_count
FROM nicknames
INNER JOIN counts
ON nicknames.USER_ID = counts.USER_ID;

MYSQL: Select and order users table by matching values, but separate column names?

I'm trying to check and order my users table who has the most origins (referals).
I have a users table, which has an 'origin' column, filled in with another users 'username' column if they refereed them, null if nobody.
Here is what I have so far, but its constantly returning 0 for the origin_count column?
SELECT username,
(SELECT COUNT(*)
FROM users
WHERE origin = username) AS origin_count
FROM users
WHERE tmp_allow_share = 1 AND approved_at IS NOT NULL;
SELECT COUNT(*) FROM users WHERE origin = username counts how many users have themselves as origin.
What you want to do is group by username and count origin (possibly distinct if you're looking for unique referals).
SELECT COUNT(origin) FROM users GROUP BY username;
You don't need a subquery to calculate origin count, rather use count directly with group by
SELECT username,
count(*) AS origin_count
FROM users
WHERE tmp_allow_share = 1
AND approved_at IS NOT NULL
GROUP BY username;

Group by gives error "Invalid use of group function"

I'd like to get the number of likes each user got from the following tables:
Users table: contains the userid, email, contact no
Like table: which contains picture ids, and userids who liked it
Picture posted table*: contains picture ids, user id who posted it
I am using the following query which is giving the error "Invalid use of group function":
select sum(count(pid)) from p_like where pid in (
select pid from p_picuser where userid in (
SELECT userid from p_users
)
) GROUP BY pid
What am I doing wrong?
You can't aggregate (sums, counts, etc) the same variables on which you're grouping by. If you'd like counts by user, group on that. So maybe try something like:
SELECT userid, count(*) from p_like GROUP BY user
to get the like-count's by userId from your p_like table. Strictly-speaking, this your answer.
To add more user details then, you can make that a sub-query and join to you p_user table, e.g.
SELECT email, like_count from p_users pusers, (
SELECT userid, count(*) like_cound from p_like GROUP BY user
) group_sub
WHERE p_users.userid = group_sub.userid

Sql statement with expression in group by

I have a question about one sql statement for my mysql db. I have a table with the following columns :-
sender_id | receiver_id | content | dateAndTime
As you understand I would like to implement sending messages between users. I want to select the last message(doesn't matter sent or received) with every user. Something like the messages in facebook. I guess that I should use expression in group by if it is possible but I would like to see your opinion how I should do it. Thanks!
For This kind of purpose, your field dateAndTime is must be date-time type.
SELECT * FROM TABLE ORDER BY dateAndTime DESC
You can retrieve latest data using this descending order.
Try this one
SELECT C.ID, T.content, T.dateAndTime FROM T JOIN
(
SELECT ID, MAX(dateAndTime) 'last' FROM
(
SELECT sender_id 'ID', content, dateAndTime FROM T
UNION
SELECT receiver_id 'ID', content, dateAndTime FROM T
) B
GROUP BY ID
) C
WHERE T.dateAndTime = C.last AND (T.sender_id = C.ID OR T.receiver_id = C.ID)
Assuming you have a 'users' table, and your stated table named 'mytable' you could:
select users.id,mytable.content, MAX(mytable.dateAndTime) as date
from users join mytable
on users.id = mytable.sender_id
or users.id = mytable.receiver_id
group by users.id, mytable.content, date
The max function will keep only the latest date from each group generated by the group by
EDIT: try this instead
select users.id, mytable.content, mytable.dateAndTime
from users join mytable
on users.id = mytable.sender_id
or users.id = mytable.receiver_id
where mytable.dateAndTime = (select max(t.dateAndTime) from mytable as t where t.receiver_id = users.id or t.sender_id = users.id)

MySQL conditional statement on NULL with subquery

Two tables:
user (id, myValue, ...)
user_preferred (id, userid, preferredValue) fk userid -> user(id)
Explanation:
user is a table of all users. user_preferred is a table of any user's preferred values. A user can be listed multiple times in user_preferred but must have different values. Query should return all users that have a myValue that matches the preferred value of the given user. $userid is the php variable of the user passed.
The Trick:
A user could have no preference, in which case there is no entry in the user_preference table. When the above query is done, I want to return every user if the given user has no preference.
Analogy:
I'm at a bar and the bartender asks me what I want to drink. I say give me everything he has that matches my preference. The first round I say I like crappy beers. So he gives me a Fosters. Second round I say I have no preference and he gives me 12 pints ranging from Bud Light to Guinness. Instead of beers, these would be users. Get it?
Query (so far):
SELECT * FROM user WHERE
IF ((SELECT preferredValue FROM user_preferred WHERE userid = $userid) IS NULL,
1,
user.myValue ANY (SELECT preferredValue FROM user_preferred WHERE userid = $userid)
)
Additional Trick:
I don't want to run "SELECT preferredValue FROM user.preferred where id = $userid" twice. Can I save the results from the first run-time and somehow use it in place of the second?
SELECT *,(SELECT preferredValue FROM user_preferred WHERE userid = $userid) AS Result FROM user WHERE
IF (Result IS NULL,1,RESULT)
To return a list of users:
SELECT o.*
FROM `user` o
WHERE o.id IN
( SELECT DISTINCT m.userid
FROM user_preferred m
WHERE EXISTS
( SELECT 1 FROM user_preferred p
WHERE p.preferredValue = m.preferredValue
AND p.userid <> m.userid
AND p.userid = $userid )
)
OR ( o.id <> $userid AND NOT EXISTS
( SELECT 1
FROM user_preferred q
WHERE q.userid = $userid
)
)