mysql particular query [closed] - mysql

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I have two table: teams and formations:
Table teams:
team_id | team_name
1 | Barcelona
2 | Real Madrid
3 | PSG
Table formations:
formation_id | team_id | module
1 | 2 | 5-3-2
2 | 1 | 4-4-2
3 | 3 | 4-4-2
4 | 2 | 4-4-3
Pratically i have need of "join" between the 2 table GROUP BY team_id but with the last "formation_id"
The result my be this:
team_id | team_name | formation_id | module
1 | Barcelona | 2 | 4-4-2
2 | Real Madrid| 4 | 4-4-3
3 | PSG | 3 | 4-4-2
Actually my query is:
SELECT *
FROM formations f
INNER JOIN teams t
ON (f.team_id = t.team_id)
GROUP BY t.team_id
With my query I selected the first insert formation for each team, instead I must select the last formations for each team.

Check this SQLFIDDLE
SELECT A.team_id,A.team_name,B.formation_id,B.module
FROM teams A,formations B
WHERE A.team_id=B.team_id
AND B.formation_id =
(
SELECT max(formation_id)
FROM formations C
WHERE C.team_id =B.team_id
)
ORDER BY A.team_id;
create table teams
(
team_id int
,team_name varchar(40)
);
create table formations
(
formation_id int
,team_id int
,module int
);
insert into teams
values
(1,'Barcelona'),(2,'Real Madrid'),(3,'PSG');
insert into formations
values
(1,2,532),(2,1,442),(3,3,442),(4,2,443);

You can find their maximum formation ID using a subquery that you will later join it with the original tables. Try this one,
SELECT a.*, c.formation_ID, c.`module`
FROM teams a
INNER JOIN
(
SELECT team_id, MAX(formation_ID) maxID
FROM formations
GROUP BY team_ID
) b ON a.team_id = b.team_id
INNER JOIN formations c
ON c.team_id = b.team_id AND
c.formation_ID = b.maxID
ORDER BY a.Team_id
SQLFiddle Demo

You can write:
SELECT t.team_id,
t.team_name,
f.formation_id,
f.module
FROM teams t
JOIN formations f
ON f.team_id = t.team_id
-- require f.formation_id to be MAX(formation_id) for some team:
JOIN ( SELECT MAX(formation_id) AS id
FROM formations
GROUP
BY team_id
) max_formation_ids
ON max_formation_ids.id = f.formation_id
;
or:
SELECT t.team_id,
t.team_name,
f.formation_id,
f.module
FROM teams t
JOIN formations f
ON f.team_id = t.team_id
-- require f.formation_id to be MAX(formation_id) for this team:
WHERE f.formation_id =
( SELECT MAX(formation_id)
FROM formations
WHERE team_id = t.team_id
)
;
or:
SELECT t.team_id,
t.team_name,
f.formation_id,
f.module
FROM teams t
JOIN formations f
ON f.team_id = t.team_id
-- forbid f.formation_id to be less than another for the same team:
LEFT
OUTER
JOIN formations f2
ON f2.team_id = t.team_id
AND f2.formation_id > f.formation_id
WHERE f2.formation_id IS NULL
;

SQL spec states that when you use group by clause then all fields/expressions in the output should be either results of aggregate functions (like count, avg, etc) or fields listed in group by clause. otherwise the behavior is not defined. So if you need to pick exactly this record you need to add some criteria to your query. Also, there is no guarantee that simple 'select * from some_table' would always return rows in the same order.

You could do something like:
select f.*, t.team_name from formations f
join (select team_id, max(formation_id) as max_formation_id from formations f
group by team_id) as mrf on mrf.max_formation_id = f.formation_id
join teams t on f.team_id = t.team_id

This version produces the same result without aggregates, which often incur internal sorting.
SELECT t.team_id,
t.team_name,
f.formation_id,
f.module
FROM teams t
INNER JOIN formations f
ON f.team_id = t.team_id
LEFT OUTER JOIN formations f2
ON f2.team_id = t.team_id
AND f2.formation_id > f.formation_id
WHERE f2.formation_id IS NULL

create table teams (team_id integer, team_name varchar(50));
create table formations (formation_id integer, team_id integer, module varchar(20));
insert into formations (formation_id, team_id, module) values
(1, 2, '5-3-2'),
(2, 1, '4-4-2'),
(3, 3, '4-4-2'),
(4, 2, '4-4-3')
;
insert into teams (team_id, team_name) values
(1, 'Barcelona'),
(2, 'Real Madrid'),
(3, 'PSG')
;
select t.team_id, team_name, f.formation_id, module
from
formations f
inner join
teams t on f.team_id = t.team_id
inner join (
select team_id, max(formation_id) as formation_id
from formations
group by team_id
) s on s.team_id = t.team_id and s.formation_id = f.formation_id
order by t.team_id
;
+---------+-------------+--------------+--------+
| team_id | team_name | formation_id | module |
+---------+-------------+--------------+--------+
| 1 | Barcelona | 2 | 4-4-2 |
| 2 | Real Madrid | 4 | 4-4-3 |
| 3 | PSG | 3 | 4-4-2 |
+---------+-------------+--------------+--------+

Related

Querying from IMDB Database using MySQL [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I wrote a SQL query to answer the following question:
Find all the actors that made more movies with Yash Chopra than any other director in the IMBD database.
Sample schema:
person
(pid *
,name
);
m_cast
(mid *
,pid *
);
m_director
(mid*
,pid*
);
* = (component of) PRIMARY KEY
Following is my query:
WITH common_actors AS
(SELECT A.actor_id as actors, B.director_id as director_id, B.movies as movies_with_director,
B.director_id as yash_chops_id, B.movies as movies_with_yash_chops FROM
(SELECT M_Cast.PID as actor_id, M_Director.PID as director_id, COUNT(*) as movies from M_Cast
left join M_Director
ON M_Cast.MID = M_Director.MID
GROUP BY actor_id, director_id) A
JOIN
(SELECT M_Cast.PID as actor_id, M_Director.PID as director_id, COUNT(*) as movies from M_Cast
left join M_Director
ON M_Cast.MID = M_Director.MID
GROUP BY actor_id, director_id
)B
ON A.actor_id = B.actor_id
WHERE B.director_id in (SELECT PID FROM Person WHERE Name LIKE
'%Yash%Chopra%'))
SELECT distinct actors as actor_id, movies_with_yash_chops as total_movies FROM common_actors
WHERE actors NOT IN (SELECT actors FROM common_actors WHERE movies_with_director > movies_with_yash_chops)
And the result obtained from this is of length: 430 rows. However the result obtained should be of length 243 rows. Could anyone please suggest where I went wrong in my query? Is my approach right?
Sample result:
Actor name
0 Sharib Hashmi
1 Kulbir Badesron
2 Gurdas Maan
3 Parikshat Sahni
...
242 Ramlal Shyamlal
Thanks in advance!
Consider the following:
DROP TABLE IF EXISTS person;
CREATE TABLE person
(person_id SERIAL PRIMARY KEY
,name VARCHAR(20) NOT NULL UNIQUE
);
DROP TABLE IF EXISTS movie;
CREATE TABLE movie
(movie_id SERIAL PRIMARY KEY
,title VARCHAR(50) NOT NULL UNIQUE
);
DROP TABLE IF EXISTS m_cast;
CREATE TABLE m_cast
(movie_id INT NOT NULL
,person_id INT NOT NULL
,PRIMARY KEY(movie_id,person_id)
);
DROP TABLE IF EXISTS m_director;
CREATE TABLE m_director
(movie_id INT NOT NULL
,person_id INT NOT NULL
,PRIMARY KEY(movie_id,person_id)
);
INSERT INTO person (name) VALUES
('Steven Feelberg'),
('Manly Kubrick'),
('Alfred Spatchcock'),
('Fred Pitt'),
('Raphael DiMaggio'),
('Bill Smith');
INSERT INTO movie VALUES
(1,'Feelberg\'s Movie with Fred & Raph'),
(2,'Feelberg and Fred Ride Again'),
(3,'Kubrick shoots DiMaggio'),
(4,'Kubrick\'s Movie with Bill Smith'),
(5,'Spatchcock Presents Bill Smith');
INSERT INTO m_director VALUES
(1,1),
(2,1),
(3,2),
(4,2),
(5,3);
INSERT INTO m_cast VALUES
(1,4),
(1,5),
(2,4),
(3,5),
(4,6),
(5,6);
I've included the movie table only for ease of reference. It's not relevant to the actual problem.
Also, note that this model assumes that cast members are only listed once, regardless of whether or not they have multiple roles in a given film.
The following query asks 'how often have each actor and director worked together'...
An actor is any person who has been a cast member of any movie.
A director is any person who has been a director of any movie.
SELECT a.name actor
, d.name director
, COUNT(DISTINCT ma.movie_id) total
FROM person d
JOIN m_director md
ON md.person_id = d.person_id
JOIN person a
LEFT
JOIN m_cast ma
ON ma.person_id = a.person_id
AND ma.movie_id = md.movie_id
JOIN m_cast x
ON x.person_id = a.person_id
GROUP
BY actor
, director;
+-------------------+-------------------+-------+
| actor | director | total |
+-------------------+-------------------+-------+
| Fred Pitt | Alfred Spatchcock | 0 |
| Fred Pitt | Manly Kubrick | 0 |
| Fred Pitt | Steven Feelberg | 2 |
| Raphael DiMaggio | Alfred Spatchcock | 0 |
| Raphael DiMaggio | Manly Kubrick | 1 |
| Raphael DiMaggio | Steven Feelberg | 1 |
| Bill Smith | Alfred Spatchcock | 1 |
| Bill Smith | Manly Kubrick | 1 |
| Bill Smith | Steven Feelberg | 0 |
+-------------------+-------------------+-------+
By observation, we can see that:
the only actor to work more often with Feelberg than any other director is Fred Pritt
Raphael DiCaprio and Bill Smith have both worked equally often with two directors (albeit different directors)
EDIT: While I'm not seriously advocating this as a solution, the following is simply to demonstrate that the kernel provided above is really all you need to solve the problem...
SELECT x.*
FROM
( SELECT a.*
FROM
( SELECT a.name actor
, d.name director
, COUNT(DISTINCT ma.movie_id) total
FROM person d
JOIN m_director md
ON md.person_id = d.person_id
JOIN person a
LEFT
JOIN m_cast ma
ON ma.person_id = a.person_id
AND ma.movie_id = md.movie_id
JOIN m_cast x
ON x.person_id = a.person_id
GROUP
BY actor
, director
) a
LEFT
JOIN
( SELECT a.name actor
, d.name director
, COUNT(DISTINCT ma.movie_id) total
FROM person d
JOIN m_director md
ON md.person_id = d.person_id
JOIN person a
LEFT
JOIN m_cast ma
ON ma.person_id = a.person_id
AND ma.movie_id = md.movie_id
JOIN m_cast x
ON x.person_id = a.person_id
GROUP
BY actor
, director
) b
ON b.actor = a.actor
AND b.director <> a.director
AND b.total > a.total
WHERE b.actor IS NULL
) x
LEFT JOIN
( SELECT a.*
FROM
( SELECT a.name actor
, d.name director
, COUNT(DISTINCT ma.movie_id) total
FROM person d
JOIN m_director md
ON md.person_id = d.person_id
JOIN person a
LEFT
JOIN m_cast ma
ON ma.person_id = a.person_id
AND ma.movie_id = md.movie_id
JOIN m_cast x
ON x.person_id = a.person_id
GROUP
BY actor
, director
) a
LEFT
JOIN
( SELECT a.name actor
, d.name director
, COUNT(DISTINCT ma.movie_id) total
FROM person d
JOIN m_director md
ON md.person_id = d.person_id
JOIN person a
LEFT
JOIN m_cast ma
ON ma.person_id = a.person_id
AND ma.movie_id = md.movie_id
JOIN m_cast x
ON x.person_id = a.person_id
GROUP
BY actor
, director
) b
ON b.actor = a.actor
AND b.director <> a.director
AND b.total > a.total
WHERE b.actor IS NULL
) y
ON y.actor = x.actor AND y.director <> x.director
WHERE y.actor IS NULL;
+-----------+-----------------+-------+
| actor | director | total |
+-----------+-----------------+-------+
| Fred Pitt | Steven Feelberg | 2 |
+-----------+-----------------+-------+
This returns a list of every actor, and the director with whom they've worked most often. In this case, because Bill Smith and Raphael DiMaggio have worked most often equally with two directors, they are excluded from the result.
The answer to your problem is simply to select from this list all rows with Yash Chopra listed as the director.

symmetric pair in sql

Given the tables student, mathematics_marks, science_marks
student
student_id (Primary Key) | smallint
student_name | varchar(30)
mathematics_marks
student_id (Primary Key) | smallint
score | float (5,2)
science_marks
student_id (Primary Key) | smallint
score | float (5,2)
A student is called as being a part of a symmetric pair if the marks obtained by that student in science is equal to the marks obtained by some other student in mathematics and the marks obtained in mathematics are the same as marks obtained by the other student in science.
Write a SQL query to print the name of the students who are a part of the symmetric pair. Order the output in order of student name.
with cte as (
select m.student_id, m.score as math_score, s.score as science_score
from mathematics_marks m inner join science_marks s
on s.student_id = m.student_id
)
select s1.student_name
from cte c1 inner join cte c2
on c2.student_id > c1.student_id and c2.math_score = c1.science_score and c1.math_score = c2.science_score
inner join student s1 on s1.student_id = c1.student_id and s1.student_id = c2.student_id
need to get the pair in two different rows?
EDITED:
answer to this
with cte as (
select m.student_id, m.score as math_score, s.score as science_score
from mathematics_marks m inner join science_marks s
on s.student_id = m.student_id
),
T as (select c1.student_id, c1.math_score, c1.science_score, s.student_name as name
from cte c1 inner join student s
on c1.student_id = s.student_id )
select t1.name from T t1 inner join T t2
on t1.math_score = t2.science_score and
t1.science_score = t2.math_score
order by t1.name
A properly designed schema would have a single table for student, subject, and mark. The first step then is to emulate that table, which could be as follows:
SELECT student_id
, 'mathematics' subject
, score
FROM mathematics_marks
UNION
SELECT student_id
, 'science'
, score
FROM science_marks
For further help, see: Why should I provide an MCRE for what seems to me to be a very simple SQL query?
It's always easy to answer if the post is accompanied by sample data and expected output . Are you looking for somthing like this
Select student.student_id
,maths.score maths_socer
,sci.score science_score
from
(
Select 1 student_id union all
Select 2 union all
Select 3
) student
Join
(
Select 1 student_id, 20 score union all
Select 2, 30 union all
Select 3, 40
) maths
on maths.student_id=student.student_id
Join
(
Select 1 student_id , 30 score union all
Select 2,20 union all
Select 3,40
) sci on sci.student_id !=student.student_id
Where sci.score = maths.score

SQL - How to find the person with the highest grade

I am trying to find the name of the person who received the highest grade in the "Big Data" course.
I have 3 different tables:
People (id, name, age, address)
---------------------------------------------------
p1 | Tom Martin| 24 | 11, Integer Avenue, Fractions, MA
p2 | Al Smith | 33 | 26, Main Street, Noman's Land, PA
p3 | Kim Burton| 40 | 45, Elm Street, Blacksburg, VA
---------------------------------------------------
Courses (cid, name, department)
---------------------------------------------------------
c1 | Systematic Torture | MATH
c2 | Pretty Painful | CS
c3 | Not so Bad | MATH
c4 | Big Data | CS
---------------------------------------------------------
Grades (pid, cid, grade)
---------------------------------------------------
p1 | c1 | 3.5
p2 | c3 | 2.5
p3 | c2 | 4.0
p3 | c4 | 3.85
---------------------------------------------------
I can't figure out how to find the person with the highest grade without using any fancy SQL feature. That is, I just want to use SELECT, FROM, WHERE, UNION, INTERSECT, EXCEPT, CREATE VIEW and arithmetic comparison operators like =, <, >.
My outcome is showing something other than what I try to achieve.
This is what I have tried so far:
CREATE VIEW TEMPFIVE AS
SELECT G1.pid FROM Grades AS G1, Grades AS G2 WHERE G1.pid = G2.pid AND G1.cid = G2.cid
SELECT People.name, Courses.name FROM TEMPFIVE, People, Courses WHERE TEMPFIVE.pid = People.pid AND Courses.name = "Big Data";
+------------+----------+
| name | name |
+------------+----------+
| Tom Martin | Big Data |
| Al Smith | Big Data |
|Kim Burton | Big Data |
|Kim Burton | Big Data |
+------------+----------+
The easiest way is to use LIMT 1 with an ORDER BY DESC clause:
SELECT p.name, c.name, g.grade
FROM People AS p
JOIN Grades AS g ON p.id = g.pid
JOIN Courses AS c ON c.cid = g.cid
WHERE c.name = "Big Data"
ORDER BY g.grade DESC LIMIT 1
No Idea for MySql Query structure. So Explained in steps. I hope you can build query based on that.
join three tables according to their relationship
set course name 'Big data' in where clause
set grade order to DESC order
set the limit to fetch only first row.
Try this
select * from(
select p.id pid,p.name name, p.age age,p.address address,
c.cid cid, c.name coursname, c.department department,g.grade grade
from Grades G
left join
Courses C on g.cid = c.cid
left join
People p on g.pid = p.id
)a where coursname= 'Big Data' order by grade desc
you can apply the operators on the where clause
GiorgosBestos shoes the correct way if you only want 1 record. If you want ties. meaning if more than 1 student has the same MAX grade then you can do a subselect as follows:
SELECT p.name, c.name, g.grade
FROM
(
SELECT c.cid, MAX(g.grade) MaxGrade
FROM
Grades g
INNER JOIN Courses c
ON c.cid = g.cid
AND c.name = 'Big Data'
GROUP BY
c.cid
) m
INNER JOIN Grades g
ON g.cid = m.cid
AND g.grade = m.MaxGrade
INNER JOIN People p
ON g.pid = p.id
The following SQL covers the case when tow or more students have the same maximum grade:
SELECT P.NAME,
C.NAME,
G.GRADE
FROM PEOPLE P
JOIN GRADES G ON G.PID = P.ID
JOIN COURSES C ON C.CID = G.CID
WHERE C.NAME = 'Big data'
AND G.GRADE = (SELECT MAX(G2.GRADE)
FROM PEOPLE P2
JOIN GRADES G2 ON G2.PID = P2.ID
JOIN COURSES C2 ON C2.CID = G2.CID
WHERE C2.NAME = 'Big data');
It is similar but not identical to the SQL proposed by Matt.

MYSQL return results where there exist at least one from the other table

Say I have these data from two table:
Student Table columns:
id | name
Course Table columns:
id | code | name
and I want to use the Student.id AS Student and Course.id AS Course
to get the following:
Student | Course
-----------------
1 | C
1 | B
1 | A
2 | F
2 | B
2 | A
3 | C
3 | B
3 | F
How would I query it so it will return only the Students with a Course C and their other Courses like below:
Student | Course
-----------------
1 | C
1 | B
1 | A
3 | C
3 | B
3 | F
?
I have tried :
SELECT Student.id, Course.code FROM Course
INNER JOIN Student ON Course.student = Student.id
WHERE Course.code = 'C'
but I got only
Student | Course
-----------------
1 | C
3 | C
SELECT s.id, c.code
FROM Course c
INNER JOIN Student s
ON c.student = s.id
WHERE EXISTS
(
SELECT 1
FROM Course c1
WHERE c.student = c1.student
AND c1.Course = 'C'
)
The most efficient approach to this problem is usually an inline view and a JOIN operation, although there are several ways to get an equivalent result.
SELECT Student.id
, Course.code
FROM ( SELECT c.Student
FROM Course c
WHERE c.code = 'C'
GROUP BY c.Student
) o
JOIN Course
ON Course.Student = o.Student
JOIN Student
ON Student.id = Course.Student
Here, we're using an inline view (aliased as o) to get a list of Student taking course code = 'C'.
(NOTE: the query in my answer is based on your original query. If there's a foreign key definition between Course and Student, and we only need to return the Student.id, we could improve performance by omitting the join to Student, and return Course.Student AS id in place of Student.id in the SELECT list.)
Here the first JOIN selects only those students which have course C, and second JOIN gives you all the courses for each of those students.
SELECT st.id, c2.code FROM
Student st
JOIN Course c ON c.student = st.id AND c.code = "C"
JOIN Course c2 ON c2.student = st.id
You actually don't even need two tables here, because both student and course is available in the Course table, just JOIN it on itself:
SELECT c2.student, c2.code FROM
Course c JOIN Course c2 ON c.student = c2.student
WHERE c.course = "C"
Here the WHERE clause leaves student id's which have course C and then you JOIN those to find all their courses.

SQL how to select unique one-to-one pairings

edited to make clearer - many apologies for the confusion of the original example
I have the following table structure representing married couples:
id | Person | Spouse
______________________
1 | Mary | John
2 | John | Mary
3 | Katy | Bob
4 | Bob | Katy
5 | Mary | John
6 | John | Mary
In this example Mary is married to John, Katy to Bob and a different Mary is married to a different John.
How can I retrieve these pairs of married couples?
I have got close with this:
SELECT
p.id id1,
q.id id2
FROM
people p
INNER JOIN people q ON
p.person = q.spouse AND
q.person = p.spouse AND
p.id < q.id
ORDER BY p.id
However this returns:
1 | 2 (1st Mary & 1st John)
1 | 6 (1st Mary & 2nd John) *problem*
2 | 5 (1st John & 2nd Mary) *problem*
3 | 4 (Katy & Bob)
5 | 6 (2nd Mary & 2nd John)
How can I make sure the 1st Mary and 1st John are only married once (i.e. remove the problem rows above)?
Many thanks
Here's the SQL to create the example:
CREATE TABLE people
(`id` int, `person` varchar(7), `spouse` varchar(7))
;
INSERT INTO people
(`id`, `person`, `spouse`)
VALUES
(1, 'Mary', 'John'),
(2, 'John', 'Mary'),
(3, 'Katy', 'Bob'),
(4, 'Bob', 'Katy'),
(5, 'Mary', 'John'),
(6, 'John', 'Mary')
;
SELECT
p.id id1,
q.id id2
FROM
people p
INNER JOIN people q ON
p.person = q.spouse AND
q.person = p.spouse AND
p.id < q.id
ORDER BY p.id
;
I'll give it a try:
SELECT
p.id AS id1,
q.id AS id2
FROM
people AS p
JOIN people AS q ON
p.person = q.spouse AND
q.person = p.spouse AND
p.id < q.id
JOIN (SELECT
p.id, COUNT(*) AS rank
FROM
people AS p
INNER JOIN people AS p2 ON
p.person = p2.person AND
p.spouse = p2.spouse AND
p.id >= p2.id
GROUP BY p.id
) AS x ON
x.id = p.id
JOIN (SELECT
p.id, COUNT(*) AS rank
FROM
people AS p
INNER JOIN people AS p2 ON
p.person = p2.person AND
p.spouse = p2.spouse AND
p.id >= p2.id
GROUP BY p.id
) AS y ON
y.id = q.id AND
y.rank = x.rank ;
And another one:
SELECT
p.id AS id1,
q.id AS id2
FROM
people AS p
JOIN people AS q ON
p.person = q.spouse AND
q.person = p.spouse
JOIN people AS p2 ON
p.person = p2.person AND
p.spouse = p2.spouse AND
p.id >= p2.id
JOIN people AS q2 ON
q.person = q2.person AND
q.spouse = q2.spouse AND
q.id >= q2.id
WHERE
p.id < q.id
GROUP BY
p.id, q.id
HAVING
COUNT(DISTINCT p2.id) = COUNT(DISTINCT q2.id) ;
Both tested at SQL-Fiddle
It would be much simpler, if only MySQL had window functions (like almost all other DBMS have). Tested at Postgres fiddle:
WITH cte AS
( SELECT
id, person, spouse,
ROW_NUMBER() OVER( PARTITION BY person, spouse
ORDER BY id )
AS rn
FROM
people
)
SELECT
p.id AS id1,
q.id AS id2
FROM
cte AS p
JOIN cte AS q ON
p.person = q.spouse AND
q.person = p.spouse AND
p.rn = q.rn AND
p.id < q.id ;
In this example Mary is married to John, Katy to Bob and a different Mary is married to Richard.
Nothing in your show data structures allows to differentiate between those two “Marys”, because there is no difference between them.
Both are just the text literal Mary. If you want to differentiate between different people that might have the same name, then you need another criterion, and a unique one at that. (F.e. the id of the database records for each individual person.)
Your database stricture is wrong.
People like Mary, John, etc. do not have identity.
Some heuristic query might help, but it is not a reliable solution.
So, please, improve you data structure.
Not very elegant, but works:
SELECT p.id, q.id
FROM people p
INNER JOIN people q ON
p.person1 = q.person2 and
q.person1 = p.person1
which in fact uses the existance of an inverted row as a selector
There's lots of ways of doing it, however one of the most important reasons for using a database is that it holds lots of data - and there should rarely be times when you ever write a query which retrieves lots of data. Except in very unusual circumstances, and for homework assignments, the results should be filtered according to some criteria. Hence the most appropriate solution depends on what other stuff you add to the query later.
But here's a couple of examples of how to get the unique pairs:
SELECT a, b, GROUP_CONCAT(id)
(SELECT id
, IF (person>=spouse, person, spouse) as a
, IF (person>=spouse, spouse, person) as b
FROM yourtable ) AS pairs
GROUP BY a,b;
SELECT id, person, spouse
FROM yourtable s1
WHERE NOT EXISTS ( SELECT 1
FROM yourtable s2
WHERE s2.id>s1.id
AND s1.person=s2.spouse
AND s1.spouse=S2.person);
(there are several other solutions).