SQL Query - All leisures of a person - php

I'm new here. I thought I could ask for some help here on my php-sql homework.
I've been trying to extract all the sports associated to a registered person using SQL.
There are three tables in my mySql.
personnes which stores the individuals
[id] [sexe] [etat_civil] [nom] [prenom]
1 Homme M. Smith Alex
2 Femme Mme Alisha Elektra
3 Femme Mll Lord Yves
loisirs which stores the types of sports or leisures
id nom
1 Sport
2 Concert
3 Jeux vidéo
4 Jeux société
5 Voyage
6 Cinéma
7 Lecture
8 Théâtre
9 Danse
10 Animaux
11 Randonnée
12 Shopping
personnes_loisirs which stores the foreign key of the individuals which associated foreign keys id.
[id] [fk_personnes] [fk_loisirs]
1 1 1
2 1 2
3 1 3
4 2 1
5 2 3
6 2 4
7 2 5
8 3 7
9 3 8
10 3 9
Basically, I've been successful to extract the sport of a user but only if there's only 1 sport associated to him. Where there are more than 1, I fail to get the rest of it.
Here's the SQL
select nom
from `loisirs`
where id in
(select fk_loisirs
from `personnes_loisirs`
where id in
(select id
from `personnes`
where sexe='Homme' AND nom='Smith' AND prenom='Alex'))
This returns me 'Sport' but not 'Sport, Concert and Jeux Vidéo';
I think I must use JOIN to be able to retrieve all the 'loisirs' associated to SmithAlex
But I'm not sure how.
Please help.

select l.nom
from personnes p
join personner_loisirs pl on p.id = pl.fk_personnes
join loisirs l on l.id = pl.fk_loisirs
where p.nom = 'Smith' and p.prenom='Alex'

Your subquery is not correct. You shouldn't say where id in... you should say where fk_personnes in...

In your original query you made an error when checking for the link between personnes_loisirs and personnes - you're returning the id from personnes in the final query but you should be using fk_personnes. Basically this is a very good demonstration of why fields just named id can be confusing...
In addition you should then measure that against another way of constructing the query e.g.
select l.nom
from personnes p
inner join personnes_loisirs pl on pl.[fk_personnes] = p.[id]
inner join loisirs l on l.[id] = pl.fk_loisirs
where p.sexe='Homme'
and p.nom='Smith'
and p.prenom='Alex'

Try this query : (not tested)
SELECT loisirs.*
FROM loisirs
INNER JOIN personnes_loisirs ON personnes_loisirs.fk_loisirs = loisirs.id
INNER JOIN personnes ON personnes_loisirs.fk_personnes = personnes.id
WHERE personnes.sexe='Homme'
AND personnes.nom='Smith'
AND personnes.prenom='Alex'
;

Related

Select Multiple Values SQL

I have a table where the data are as follow
ID Classroom Person
1 1 Alfred
2 1 Maria
3 2 Maria
4 2 Zoe
5 2 Alfred
6 3 Nick
7 3 Paul
8 3 Mike
9 3 Alfred
10 4 Zoe
11 4 Maria
I want to select and return only the Classroom that has as Person only 'Alfred' and 'Maria'
Following statement :
Select * from table_name where (Person='maria') and (Person=Alfred')
doesn't seem to work.
You can see a SQL Fiddle here,
You can use group by and having:
select classroom
from table t
group by classroom
having count(*) = 2 and
sum(person in ('maria', 'Alfred')) = 2;
This assumes that one person cannot be in a classroom multiple times.
This checks that there are two names in the classroom and they are for the two names of interest. If you can have duplicates, you would want:
having count(distinct name) = 2 and
count(distinct case when person in ('maria', 'Alfred') then person end) = 2;
Try this. Group by and having with Count should work.
SELECT Classroom
FROM tablename
WHERE Person IN( 'maria', 'Alfred' )
GROUP BY classroom
HAVING Count(Person) = 2

Query and table - MAX and Join

Still very new to all of this so bear with me.
Have 3 tables
table 1: member
Mem_index, Mem_name
1 joe
2 Mark
Table 2: Course
Course_index, Course_Name
1 Math
2 Reading
Table 3 : data
Data index,Member,Course,Score
1 1 1 85
2 1 2 75
3 2 1 95
4 1 2 65
SO what I would like to do is create a table:
Do a query and gather all of the courses, find the max score for each course and attribute the member name to it.
Table result should look like:
Course, Max score,name
Math 95 Mark
Reading 75 Mark
I can do the query individually but unsure of how to loop it and then propogate the data into the table.
How about this query for SQL?
SELECT c.course_name, MAX( d.score ), m.mem_name
FROM members m
JOIN data d on m.mem_id = d.member
JOIN course c on c.course_id = d.course
GROUP BY d.course
ORDER BY d.score, m.mem_name, c.course_name
Not sure if the field names match up but you get the idea - tested this in sql with some dummy data.
Data
Index Member Course Score
1 1 1 60
1 1 1 85
Course
course_id course_name
1 Math
2 English
3 Science
Members
mem_id mem_name
1 Mark
2 James
You will get the following
Course Name Score Member
Math 85 Mark
Try this query :
SELECT c.course_Name , MAX(d.score),m.mem_name
FROM data d
JOIN course c ON d.course=c.course_index
JOIN members m ON m.mem_index = d.member
GROUP BY d.course
ORDER by MAX(d.score) DESC

Advanced mysql queries, fetching from several tables and rows at once. Joins?

I'm currently working on a project where I have information stored in several tables that all connect to each other. I believe that the table and column format is logical and the best choice. The problem though, is that I don't have enough knowledge to build queries advanced enough to fetch all the information I need.
The main table is ab_ads, where advertisements are stored. These ads can be assigned several formats (ie. 250x360, 980x120 etc), and you can also select the region where they should be showing (ie. Skåne, Stockholm, Kalmar, Dalarna, Jämtland etc).
This is how I store my data. I'm not showing all tables but I hope this is sufficient.
Advertisements column (ab_ads): (There are more columns but they are not relevant)
ID orgnum company_name title content link
1 556664-7524 Company Inc Lorem ipsum Lorem ipsum URL
Advertisement states (ab_ads_states):
ID adID stateID
1 1 2 // Skåne
2 1 5 // Kalmar
3 1 8 // Stockholm
4 1 10 // Värmland
5 2 2 // Skåne
6 2 5 // Kalmar
7 3 8 // Stockholm
8 4 10 // Värmland
Advertisement formats (ab_ads_formats)
ID adID formatID
1 1 1 // 250x360
2 1 2 // 980x120
3 2 1 // 250x360
4 3 2 // 980x120
Formats table (ab_formats)
ID name width height
1 Format 1 250 360
2 Format 2 980 120
So, I have two flash banners both are supposed to call a PHP-script which in turn is supposed to deliver an XML-file back with all the results.
I know how to select data from different tables, but I've never worked with selecting multiple rows from another table and merging them into one, which I suppose is that I need to do here. I'm very thankful for any help I can get.
The flash banners will send two parameters to the PHP file, stateID and formatID. Which means I have to SELECT ad WHERE state = param AND format = format. But since I store multiple entries for the ad states I don't know how to do it.
EDIT:
I would also like to fetch the format names in the query and get them in the following format: "Format 1,Format 2" in a column named "formats". I guess this would require some kind of join?
Thanks in advance!
I think this will work:
select ab.name as formats, aa.* from ab_ads as aa
inner join ab_ads_states as aas on aa.id = aas.adid and aas.stateId = stateIdParam
inner join ab_ads_formats as aaf on aa.id = aaf.adid and aaf.formatId = formatIdParam
inner join ab_formats as ab on aaf.formatid = ab.id
Edit:
I'm not very good with mySql, and don't have anything to test this on, but I think group_concat may be what you are looking for. If so, it will probably look something like this:
select group_concat(ab.name separator ", ") as formats from ab_ads aa
inner join ab_ads_states as aas on aa.id = aas.adid and aas.stateId = 2
inner join ab_ads_formats as aaf on aa.id = aaf.adid and aaf.formatId in(1,2)
inner join ab_formats as ab on aaf.formatid = ab.id
group by ab.id
Please try below SQL:
SELECT count(aaf.ID) AS TotalFormat,
group_concat(ab.name) AS formats
FROM ab_ads aa
INNER JOIN ab_ads_states AS aas ON aa.ID = aas.adID
AND aas.stateID = 2
INNER JOIN ab_ads_formats AS aaf ON aa.id = aaf.adID
AND aaf.formatID in(1,2)
INNER JOIN ab_formats AS ab ON aaf.formatID = ab.ID
GROUP BY aaf.adID HAVING TotalFormat >=2
SQL Demo: http://sqlfiddle.com/#!2/9f0ab/10

SUM acorrding to another column

I need to know if there is a possible way doing this with out subquery..
Here is my table structure:
id-name-father_id
1 joe 0
2 mark 0
3 muller 0
4 miki 2
5 timi 2
6 moses 2
7 david 1
8 momo 0
9 daniel 0
10 ermi 3
My table logic is
0 means he is not a child of some one
1+ mean that he is son of man in that row.
Note: if some one have a child, he still
will have 0 in father id (it's mean there is not grand-fathers in my table)
My query is :
SELECT id, name, count(id=father_id) as sons
WHERE father_id = 0
What I want to get is a list of non-children (father_id=0) and sum
the childrens it has.
Is there a way to get the results without a subquery?
This should do it (MySQL):
SELECT `parents`.`id`, `parents`.`name`, COUNT(`children`.*) AS sons
FROM `people` AS parents
LEFT JOIN `people` AS children ON `parents`.`id` = `children`.`father_id`
WHERE `parents`.`father_id` = 0
GROUP BY `parents`.`id`
According to Gary we need to add name to GROUP BY in other SQL databases:
SELECT `parents`.`id`, `parents`.`name`, COUNT(`children`.*) AS sons
FROM `people` AS parents
LEFT JOIN `people` AS children ON `parents`.`id` = `children`.`father_id`
WHERE `parents`.`father_id` = 0
GROUP BY `parents`.`id`, `parents`.`name`
We are joing the table with itself here. So we join all parents with their children.
This will lead to a result like that:
parents.id parents.name children.id children.name
1 joe 7 david
2 mark 4 miki
2 mark 5 timi
2 mark 6 moses
3 muller 10 ermi
8 momo - - # left join allows this line
9 daniel - -
But now we have each parent several times. So we are GROUP'ing the whole thing over the parent’s id, which will result in the following:
parents.id parents.name COUNT(children.*)
1 joe 1
2 mark 3
3 muller 1
8 momo 0
9 daniel 0
You should be able to do it without any joins or sub-queries as follows:
select case father_id when 0 then id else father_id end id,
max(case father_id when 0 then name end) name,
sum(sign(father_id)) sons
from table
group by case father_id when 0 then id else father_id

Help with limiting a joined mysql database query

I have written a query which returns all records with some many-to-many joins correctly for the entire set or an individual article using WHERE a.id = ?
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id
LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id
LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id
LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
BUT!
I've hit a brick wall trying to work out how to limit the articles to a specific number of IDs, for working with pagination.
I'm ideally trying to use as simple and clear SQL statements as possible because I'm using the codeigniter framework with their active record class.
http://codeigniter.com/user_guide/database/active_record.html
Would really appreciate some help as I don't want to revert to using multiple queries for this as I've tried to reduce it down to a single query for database efficiency.
Have search around and tried some alternatives but nothing seems to work. Many thanks!
For example the results I return are like this
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
2 test 2 2 1 1
2 test 2 1 2 1
2 test 2 1 1 2
2 test 2 5 1 1
2 test 2 8 1 1
2 test 2 1 4 1
2 test 2 1 4 2
I need the results like this so that I can create sub-arrays in the php like this:
$articles = $query->result_array();
$output = array();
foreach ($articles as $article) {
// set up article details
$article_id = $article['id'];
// add article details
$output[$article_id]['article_id'] = $article_id;
$output[$article_id]['date_added'] = $article['date_added'];
$output[$article_id]['title'] = $article['title'];
$output[$article_id]['content'] = $article['content'];
// set up people details and add people array with details if exists
if (isset($article['person_id'])) {
$person_id = $article['person_id'];
$output[$article_id]['people'][$person_id]['person_id'] = $person_id;
$output[$article_id]['people'][$person_id]['lastname'] = $article['lastname'];
$output[$article_id]['people'][$person_id]['firstname'] = $article['firstname'];
}
// set up organizations details and add organizations array with details if exists
if (isset($article['organization_id'])) {
$organization_id = $article['organization_id'];
$output[$article_id]['organizations'][$organization_id]['organization_id'] = $organization_id;
$output[$article_id]['organizations'][$organization_id]['organization_name'] = $article['organization_name'];
}
// set up categories details and add categories array with details if exists
if (isset($article['category_id'])) {
$category_id = $article['category_id'];
$output[$article_id]['categories'][$category_id]['category_id'] = $category_id;
$output[$article_id]['categories'][$category_id]['category_name'] = $article['category_name'];
}
}
But if I just use LIMIT (with offset etc) 1
the results I get are
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
instead of
---------------------------------------------------------------------
id title category_id person_id organization_id
---------------------------------------------------------------------
1 test 1 1 1
1 test 2 1 1
1 test 1 2 1
1 test 1 1 2
1 test 5 1 1
1 test 8 1 1
1 test 1 4 1
1 test 1 4 2
1 test 1 1 1
which is my desired result.
OK, so finally I worked out how it is possible.
Thought i'd include it here in case anyone else has the same problem.
Changing this line
FROM articles AS a
to this
FROM (SELECT * FROM articles LIMIT 5,3) AS a
does what I wanted.
So, why don't you use OFFSET 0,10 and LIMIT *number_of_results* in the SQL Query? (if I understood the question)
Specific number of IDs... WHERE ID IN (2,4,6,8)... ?
Are you using codeigniter's pagination?
http://codeigniter.com/user_guide/libraries/pagination.html
You can easily limit the number of records that are being returned using the MySQL LIMIT clause. This can be achieved like the following with your sample query.
SELECT a.id, date_added, title, content, category_id, person_id, organization_id, c.name AS category_name, firstname, lastname, o.name AS organization_name
FROM articles AS a
LEFT OUTER JOIN articles_categories AS ac ON a.id=ac.article_id LEFT OUTER JOIN categories AS c ON c.id=ac.category_id
LEFT OUTER JOIN articles_people AS ap ON a.id=ap.article_id LEFT OUTER JOIN people AS p ON p.id=ap.person_id
LEFT OUTER JOIN articles_organizations AS ao ON a.id=ao.article_id LEFT OUTER JOIN organizations AS o ON o.id=ao.organization_id
ORDER BY date_added
LIMIT 10
Where 10 is the number of records you wish to display. The MySQL LIMIT clause allows you to specify a limit of the number of records and an initial offset. Like so:
LIMIT <offset>,<limit>
In your case <offset> would be the current page * the number of records on a page. <limit> would be the number of records you would like to display per page.

Categories