Joining the same table to get the information - mysql

I have a table like
Name Spouse
---------------
John Smitha
Bob Neetha
Neetha Bob
Mona Jack
Smitha John
Jack Mona
and I want results as below using joins in MySQL.
Name Spouse
---------------
John Smitha
Bob Neetha
Mona Jack
(i.e. the couple should be selected only once)

Assuming that you have a IsPrimary field.
You could easily achieve this with the following query.
SELECT P.NAME, S.NAME As SpouseName
FROM PEOPLE P
LEFT JOIN PEOPLE S ON P.Spouse = S.Spouse -- You should have a PK/FK relasionship here (SouseId) and not join on a name string
WHERE P.IsPrimary = 1

a way to do it like that
SELECT `Name`, `Spouse`
FROM Table1
WHERE `Name` <= `Spouse`
demo

Related

SQL "chained" queries?

I have two tables.
I am a total newbie to SQL. Using mysql at the moment.
I have the following setup for a school-related db:
Table A contains students records.
Student's id, password,name, lastname and so on.
Table B contains class attendancy records.
Each record goes like this: date, student id, grade
I need to gather all the student info of students that attended classes in a certain date range.
Now, the stupid way would be
first I SELECT all classes from Table B with DATE IN BETWEEN the range
then for each class, I get the student id and SELECT * FROM students WHERE id = student id
What I can't wrap my mind around is the smart way.
How to do this in one query only.
I am failing at understanding the concepts of JOIN, UNION and so on...
my best guess so far is
SELECT students.id, students.name, students.lastname
FROM students, classes
WHERE classes.date BETWEEN 20140101 AND 20150101
AND
classes.studentid = students.id
but is this the appropriate way for this case?
Dont add the join statement in the where clause. Do it like this:
SELECT s.id, s.name, s.lastname,c.date,c.grade
FROM classes c
inner join students s
on c.studentid=s.id
WHERE c.date BETWEEN '01/01/2014' AND '01/01/2015'
This sounds like an assignment so I will attempt to describe the problem and give a hint to the solution.
An example of a union would be;
SELECT students.name, students.lastname
FROM students
WHERE students.lastname IS NOT NULL
UNION
SELECT students.name, 'N/A'
FROM students
WHERE students.lastname IS NULL;
+--------------+--------------+
| name | lastname |
+--------------+--------------+
| John | Doe | <- First two rows came from first query
| Jill | Smith |
| Bill | N/A | <- This came from the second query
+--------------+--------------+
The usual use case for a union is to display the same columns, but munge the data in a different way - otherwise you can usually achieve similar results through a WHERE clause.
An example of a join would be;
SELECT authors.id, authors.name, books.title
FROM authors LEFT JOIN books ON authors.id = books.authors_id
+--------------+--------------+------------------+
| id | name | title |
+--------------+--------------+------------------+
| 1 | Mark Twain | Huckleberry Fin. |
| 2 | Terry Prat.. | Good Omens |
+--------------+--------------+------------------+
^ First two columns from ^ Third column appended
from authors table from books table linked
by "author id"
Think of a join as appending columns to your results, a union is appending rows with the same columns.
In your situation we can rule out a union as you don't want to append more student rows, you want class and student information side by side.

avoid select with subselect

I have a table with people and language this person knows. For ex
Name Language
John Engl ish
Bill English
John German
Bill Japanese
Li Chinese
I want to select all people knowing English and German languages.
The simple way is to do it:
select name from persons p where
exists (select 1
from persons pp
where pp.name=p.name
and pp.language="English")
AND
exists (select 1 from persons pp
where pp.name=p.name
and pp.language="English")
Complexity of request is n^2;
But, what if I need to select all persons knowing English, German and Russian? I'll have complexity n^3. And so on..
Is there any faster way to do it?
You want the names of people that speak both English and Japanese; not the name of people that either English or Japanese, correct? If so, here's a way of doing it without any joins or subqueries:
select name, count(name)
from persons
where language in ('English', 'Japanese')
group by name
having count(name)=2
If you need to add more languages, just add the additional languages to the where clause, and increase the number in the last line to the number of languages that you have.
Try this:
select name from persons p where p.language in ('English', 'German', 'Russian');
Try this one select
Select name from (
Select name, GROUP_CONCAT(DISTINCT language
ORDER BY language ASC SEPARATOR ' ') as gr from persons group by name) as t
WHERE gr = 'English Russian';
But this one will work for exact matches. You can use INSTR mysql function for searching in more languages.
However, my main advice is to create another structue because you have got many-to-many relations.
Revise Table Structure to:
people
person_id | name
----------+------
1 | John
2 | Bill
3 | Li
languages
language_id | language
------------+---------
1 | English
2 | German
3 | Japanese
4 | Chinese
people_have_languages
person_id | language_id
----------+------------
1 | 1
2 | 1
1 | 2
2 | 3
3 | 4
Now you that you would have a normalized table structure, here would be your query:
SELECT
`people`.`name`
FROM
`people`
INNER JOIN `people_have_languages` ON (`people`.`person_id`=`people_have_languages`.`person_id`)
INNER JOIN `languages` ON (`people_have_languages`.`language_id`=`languages`.`language`)
WHERE
`language` IN ('English', 'German', 'Russian')
GROUP BY
`people`.`person_id`

mysql - how to query a table, group by name and count of titles in the same table?

Trying to wrap my head around this query, and have tried grouping, but no luck:
If I have a table:
name title (some other fields)
John Doe Engineer ...
John Doe Tech ...
John Doe Tech ...
Frank Smith Tech ...
Frank Smith Tech ...
I need a query that would result in:
name title count(title)
John Doe Engineer 1
John Doe Tech 2
Frank Smith Tech 2
Have tried using group by name and title, but it seems to just group one or the other, giving me the count of either total engineers (1) and techs (4), or total clients (2), but I need total titles BY name.
Any suggestions?
Don't know why wouldn't this work:
SELECT name, title, COUNT(*) Titles
FROM YourTable
GROUP BY name, title
try this
SELECT name , title , count(*) count
FROM Table1
GROUP BY name , title
ORDER BY count
DEMO SQLFIDDLE
SELECT NAME, TITLE, COUNT(*) FROM BOOKS GROUP BY NAME, TITLE

Query with GROUP_CONCAT not working

I have 3 tables with the following structure:
**users**
id
first_name
last_name
**specialties**
specialty_id
specialty_name
**user_specialties**
user_id
specialty_id
Here is some sample data:
**users**
1 Bill Smith
2 Tom Jones
3 Jill Hayes
**specialties**
1 word
2 web
3 database
**user_specialties**
1 1
2 1
2 3
3 2
3 3
I need to query the data so the specialties are concatinated on one row like the below output
**Desired Result**
Bill Smith word
Tom Jones word,database
Jill Hayes web,database
I am using the following query
SELECT
users.first_name,
users.last_name,
GROUP_CONCAT(specialties.specialtyname)
FROM
users
LEFT JOIN user_specialties ON user_specialties.user_id = users.userid
RIGHT JOIN specialties ON user_specialties.specialty_id = specialties.specialty_id
It is not working...
You're missing a GROUP BY clause. Most likely it should be GROUP BY users.id, and it'd go AFTER the JOIN lines.
I just tested this query
SELECT first_name,last_name,group_concat(specialty_name)
FROM user_specialties map
INNER JOIN specialties skill on user.id = map.user_id
INNER JOIN users user ON skill.specialty_id = map.specialty_id
GROUP BY user.id
Cheers! :-)

recordset advance query

I'd like to have a query for the first and last name on an enrollment list so that only one result show. However, if only the last name is chosen in the query multiple answers will show.
You can GROUP BY the last name field in your query.
For example if you had this data:
MyTable:
id last_name first_name
1 Smith John
2 Smith Jane
3 Jones Paul
Running a query like this:
SELECT t.last_name
FROM MyTable t
GROUP BY t.last_name
ORDER BY t.last_name
...would return these two rows:
Jones
Smith