Solving mysql query - mysql

Part 1:
Software: Mysql workbench
Objective: To find the 2nd match for a particular user
Table: Profile_match
Columns: a_profile_id, b_profile_id, a_profile_match_available_on, b_profile_match_available_on
My process:
Find all the matches for a particular user
Find all the dates of the match for that user
Find the 2nd match (id, date) for that user
My Queries:
select * from profile_match
where (a_profile_id = '*****' and a_profile_match_available_on is not null)
or (b_profile_id = '*****' and b_profile_match_available_on is not null)
order by a_profile_match_available_on asc limit 1,1;
Complication:
A particular user can be either under a_profile_id or b_profile_id, so the date he is match can be a_profile_match_available_on or b_profile_match_available_on
The 'order by' doesn't help as the required date can be either on a_profile_match_available_on or b_profile_match_available_on
As seen in the photo (after export to excel), the highlighted profile id is the user I am looking at, and the highlighted dates are the day the user receive the match.
Desired outcome:
Outcome 1: Maybe can create a new column containing all the id of people matched with that user (non-highlighted id) and another column containing the all the highlight dates
Outcome 2: Maybe just have 4 columns. 1 column is id of user, 1 column is id of the user match, 1 column is date user is match, 1 column is date where user's match is match
~~~~Illustrated by User Dharmesh Patel~~~~: fiddle
The 2nd problem is that this query is only for a particular user. How do I expand this such that I can find the 2nd match for all my users?
Part 2:
Objective:
To find the 2nd mutual like for all users
Current progress: I can find the 2nd mutual like for a particular user, but my query can't do it for all my user
Query:
select * from profile_match
where (a_profile_id = '*****'
or b_profile_id = '*****')
and (a_profile_match_status = 1 and b_profile_match_status = 1)
order by created_on asc limit 1,1;
Info: a_profile_match_status and b_profile_match_status only takes value of 0 or 1. When both is 1, it means both users like each other. Created_on is simply the date both users indicate like.
Thanks guys!

For Part 1 you can try following query:
SELECT * FROM profile_match
WHERE (a_profile_id = 1 AND a_profile_match_available_on is not null)
OR (b_profile_id = 1 AND b_profile_match_available_on is not null)
ORDER BY (case when a_profile_id=1
THEN a_profile_match_available_on
ELSE b_profile_match_available_on end
) asc limit 1,1;
check following fiddle
UPDATE
check following modified queries:
PART 1
SELECT * FROM (SELECT P1.* FROM
(SELECT
a_profile_id AS profile_id,
a_profile_match_available_on as profile_match_available_on
FROM profile_match
UNION SELECT
b_profile_id AS profile_id,
b_profile_match_available_on as profile_match_available_on
FROM profile_match) AS P1
) AS P2
GROUP BY P2.profile_id
HAVING P2.profile_id=1 AND
profile_match_available_on > MIN(profile_match_available_on);
PART 2
SELECT * FROM (SELECT P1.* FROM
(SELECT
a_profile_id AS profile_id,
a_profile_match_available_on as profile_match_available_on
FROM profile_match
UNION SELECT
b_profile_id AS profile_id,
b_profile_match_available_on as profile_match_available_on
FROM profile_match) AS P1
) AS P2
GROUP BY P2.profile_id
HAVING profile_match_available_on > MIN(profile_match_available_on);

Related

Mysql how to group by multiple columns, and select a flag value based on which group matched

Suppose I want to take all duplicate values of a table by following matched criteria's:
1- matched by (first_name,last_name,father_name).
2- matched by (nationalId).
3- matched by (phone_number).
Suppose I want to get all users whose registered them self more than one using above conditions.
Now i want to take those duplicate records, along the other columns a i need to select a a column matched_type that should has one of these 1,2,3 values based on what matched occurred.
Now i have separate query for each matching criteria, is it possible to do it with one query?
I have these queries:
SELECT u.first_name,u.last_name,u.father_name,u.national_id,u.phone,COUNT(u.id) AS total,'1' AS match_type
FROM users
GROUP BY CONCAT(u.first_name,u.last_name,u.father_name)
HAVING total > 1
and for second matching criteria:
SELECT u.first_name,u.last_name,u.father_name,u.national_id,u.phone,COUNT(u.id) AS total, '2' AS match_type
FROM users
GROUP BY u.national_id
HAVING total > 1
and for the last one:
SELECT u.first_name,u.last_name,u.father_name,u.national_id,u.phone,COUNT(u.id) AS total, '3' AS match_type
FROM users
GROUP BY u.phone
HAVING total > 1
And then i have like this:
SELECT src.* FROM (first_query UNION ALL second_query UNION ALL third_query)
Pls check is this ok?
SELECT first_name,last_name, father_name, nationalId, phone_number ,CASE
WHEN first_name=[Value] AND last_name=[Value] AND father_name = [VALUE] THEN 1
WHEN nationalId=[VALUE] THEN 2
WHEN phone_number=[VALUE] THEN 3
ELSE 0 END as matched_type FROM [TABLE_NAME] WHERE
(first_name=[Value] AND last_name=[Value] AND father_name = [VALUE])
OR nationalId=[VALUE] OR phone_number=[VALUE]

Mysql: Getting the 2nd earliest date for each group

Desired outcome:
I want to get the 2nd earliest date for each group.
Current:
I am getting the earliest date for each group
Query:
select * from
(select * from profile_match
where match_available_on is not null
order by profile_id asc, match_available_on asc)
as P1
group by P1.profile_id
Example: Link
From the example, I want to get:
1, '2015-05-20 03:50:11'
2, '2015-05-16 03:50:09'
And I hope that the query is not hard-coded with specific profile_id (1 or 2) as my actual data got lots of profile_id. Thanks guys!
This query will give you the results you want:
select t.profile_id, min(t.match_available_on )
from profile_match t
inner join (
select profile_id, min(match_available_on) match_available_on
from profile_match
group by profile_id
) q
on t.profile_id = q.profile_id
and t.match_available_on > q.match_available_on
group by t.profile_id;
By finding the minmatch_available_on, we can then range join against that, and choose the minimum joined value. This isn't going to be amazingly performant, but it will get the job done.
updated your demo here.
It will not return a row for a profile which has only one date available, as there is no 'second earliest'.

MySQL Query to find row duplicates based on condition with limit

I have two tables:
Members:
id username
Trips:
id member_id flag_status created
("YES" or "NO")
I can do a query like this:
SELECT
Trip.id, Trip.member_id, Trip.flag_status
FROM
trips Trip
WHERE
Trip.member_id = 1711
ORDER BY
Trip.created DESC
LIMIT
3
Which CAN give results like this:
id member_id flag_status
8 1711 YES
9 1711 YES
10 1711 YES
My goal is to know if the member's last three trips all had a flag_status = "YES", if any of the three != "YES", then I don't want it to count.
I also want to be able to remove the WHERE Trip.member_id = 1711 clause, and have it run for all my members, and give me the total number of members whose last 3 trips all have flag_status = "YES"
Any ideas?
Thanks!
http://sqlfiddle.com/#!2/28b2d
In that sqlfiddle, when the correct query i'm seeking runs, I should see results such as:
COUNT(Member.id)
2
The two members that should qualify are members 1 and 3. Member 5 fails because one of his trips has flag_status = "NO"
You could use GROUP_CONCAT function, to obtain a list of all of the status ordered by id in ascending order:
SELECT
member_id,
GROUP_CONCAT(flag_status ORDER BY id DESC) as status
FROM
trips
GROUP BY
member_id
HAVING
SUBSTRING_INDEX(status, ',', 3) NOT LIKE '%NO%'
and then using SUBSTRING_INDEX you can extract only the last three status flags, and exclude those that contains a NO. Please see fiddle here. I'm assuming that all of your rows are ordered by ID, but if you have a created date you should better use:
GROUP_CONCAT(flag_status ORDER BY created DESC) as status
as Raymond suggested. Then, you could also return just the count of the rows returned using something like:
SELECT COUNT(*)
FROM (
...the query above...
) as q
Although I like the simplicity of fthiella's solution, I just can't think of a solution that depends so much on data representation. In order not to depend on it you can do something like this:
SELECT COUNT(*) FROM (
SELECT member_id FROM (
SELECT
flag_status,
#flag_index := IF(member_id = #member, #flag_index + 1, 1) flag_index,
#member := member_id member_id
FROM trips, (SELECT #member := 0, #flag_index := 1) init
ORDER BY member_id, id DESC
) x
WHERE flag_index <= 3
GROUP BY member_id
HAVING SUM(flag_status = 'NO') = 0
) x
Fiddle here. Note I've slightly modified the fiddle to remove one of the users.
The process basically ranks the trips for each of the members based on their id desc and then only keeps the last 3 of them. Then it makes sure that none of the fetched trips has a NO in the flag_status. FInally all the matching meembers are counted.

Group by user and show latest in MYSQL not working

I have a social network I am coding but it's a bit different than others, in this case there is only ever one status show per user on a feed section.
So I need to sort the status by date with the latest ones on top but also group by the userID
unfortunately I can't seem to get this working....
This is my current query:
SELECT *
FROM status
WHERE userID != "83" #This is just so my statuses don't show
GROUP BY userID
ORDER BY addedDate DESC
LIMIT 10
I expect to see the latest status results and only one per user instead I see the first statuses so the group by is working but not the order by.
Thanks in advance.
As mentioned in the comments to Robin's answer, that approach is unreliable because MySQL does not guarantee that it will always return the most recent status from each group. You must instead join your table with a subquery that selects the most recent status (based on addedDate).
SELECT *
FROM status
NATURAL JOIN (
SELECT userID, MAX(addedDate) as addedDate
FROM status
GROUP BY userID
) AS mostRecent
ORDER BY addedDate DESC
LIMIT 10
Note that if a user has multiple status updates with the same addedDate, the server will return all of them (whereas Robin's query would return an indeterminate one); if you need control over such a situation, you will need to define how one determines which such status update should be selected.
SELECT userID, max(addedDate)
FROM status
WHERE userID != "83" #This is just so my statuses don't show
GROUP BY userID
SELECT *
FROM ( SELECT *
FROM status
WHERE userID != "83"
ORDER BY addedDate DESC) AS h
GROUP BY userID
ORDER BY addedDate DESC
LIMIT 10
You must ORDER BY before GROUP BY'ing.
Example 1
Example 2

database query help wanted

Is it possible to limit the results a mysql select query returns with a condition?
For example I have a reviews table:
review_id, member_id, text, date
And I'd like to get the latest 10 reviews but member_id = 123 should only be taken once
Can this be achieved with a single query?
My interpretation of the problem:
the 10 most recent reviews
including at most 1 review with member_id = 123
I'm going to solve this by:
starting with the full reviews result set
removing all reviews that have member_id = 123 except for the most recent one
from the modified result set, take the 10 most recent
Here's the query:
create view newest123 as ( -- this gets the newest review for member_id 123
select *
from reviews
where member_id = 123
order by date desc limit 1
)
select *
from (
select * from newest123
union
select * -- all the reviews that aren't for member_id 123
from reviews
where member_id != 123) filtered
order by date desc limit 10 -- sort 'em and take the top 10