![]() | |
![]() |
| | Thread Tools | Display Modes |
#1
| ||||
| ||||
|
|
Field | Type | Null | Key | +-------------------------------------+--------------+------+-----+ id | int(11) | NO | PRI | username | varchar(255) | YES | | staff_group_id | int(11) | YES | MUL | |
|
Field | Type | Null | Key | Default | Extra | +------------------+---------+------+-----+---------+----------------+ id | int(11) | NO | PRI | NULL | auto_increment | position | int(11) | YES | | NULL | | staff_group_id | int(11) | YES | MUL | NULL | | profile_field_id | int(11) | YES | MUL | NULL | | +------------------+---------+------+-----+---------+----------------+ |
|
Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ id | int(11) | NO | PRI | NULL | auto_increment | name | varchar(255) | YES | | NULL | | content_type | varchar(10) | YES | | NULL | | position | int(11) | NO | | 999 | | +--------------+--------------+------+-----+---------+----------------+ |
|
Field | Type | Null | Key | Default | Extra | +--------------------+---------+------+-----+---------+----------------+ id | int(11) | NO | PRI | NULL | auto_increment | content | text | YES | | NULL | | is_visible_on_site | int(11) | YES | | 1 | | person_id | int(11) | YES | MUL | NULL | | profile_field_id | int(11) | YES | MUL | NULL | | +--------------------+---------+------+-----+---------+----------------+ |
#2
| ||||
| ||||
|
|
1. I know the person's username initially, but not their id or staff_group, which I need to determine in order to subsequently find which data applies to the user (which is connected by these fields). These are obtained from the table 'person': +-------------------------------------+--------------+------+-----+ | Field | Type | Null | Key | +-------------------------------------+--------------+------+-----+ | id | int(11) | NO | PRI | | username | varchar(255) | YES | | | staff_group_id | int(11) | YES | MUL | (I've omitted other fields from this table description, which are not of use here) SELECT id, staff_group_id FROM person where username= [username value from a PHP variable I already have]; 2. Now knowing the staff_group_id for the user, I need to find which profile fields (profile_field_id) are available to members of that staff group, from the 'profile_template' table: +------------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | position | int(11) | YES | | NULL | | | staff_group_id | int(11) | YES | MUL | NULL | | | profile_field_id | int(11) | YES | MUL | NULL | | +------------------+---------+------+-----+---------+----------------+ This would be something like: SELECT position, profile_field_id from profile_template WHERE staff_group_id = [the staff group id of my user, that I'd just already looked up] ; At this point I get stuck: I have a feeling a JOIN of some kind will be necessary, but I'm afraid that I haven't quite had a lightbulb moment regarding joins and don't fully understand them properly. |

|
Is it possible to combine the two queries above into one combined query? (I would be expecting to obtain several profile_field_id values for the particular staff group.) 3. Unfortunately, there's more. The profile_field_id above is an index into another table (profile_field) which contains what is essentially metadata about each profile field (ie, name, type, viewing order). So, for *each* profile_field_id found from above, I would need all data for (only) the profile fields that match the found ids (still with me?). profile_template.profile_field_id matches profile_field.id (profile_field table described below) +--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | content_type | varchar(10) | YES | | NULL | | | position | int(11) | NO | | 999 | | +--------------+--------------+------+-----+---------+----------------+ |
|
4. And even more (this is the final constraint!). Having obtained the data so far, I finally need to obtain the "actual" data for the profile fields which actually apply to the specific user. These are stored in yet another table (profile_record): +--------------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | content | text | YES | | NULL | | | is_visible_on_site | int(11) | YES | | 1 | | | person_id | int(11) | YES | MUL | NULL | | | profile_field_id | int(11) | YES | MUL | NULL | | +--------------------+---------+------+-----+---------+----------------+ Here, person_id is the id of the person (as found in part 1), and profile_field_id is the id (ie, type) of the field as described in the profile_field table. |

|
For safety, do I need to somehow make this one atomic action? Or can I safely do this as a series of queries, with the data obtained at each stage being transferred into and out of PHP variables as appropropriate (which would be much easier, I think!) |
#3
| |||||||
| |||||||
|
|
I'm trying to select data from an existing database (not designed by me), but the data that I need to extract is stored within several tables. |
|
In short, what I need to do is get some user "profile information" for a given user where each user is a member of exactly one 'staff group' and each staff group has different profile information fields available to it (a subset of the fields available). To get the data I need, I have to carry out the following steps: 1. I know the person's username initially, but not their id or staff_group, which I need to determine in order to subsequently find which data applies to the user (which is connected by these fields). These are obtained from the table 'person': +-------------------------------------+--------------+------+-----+ | Field | Type | Null | Key | +-------------------------------------+--------------+------+-----+ | id | int(11) | NO | PRI | | username | varchar(255) | YES | | | staff_group_id | int(11) | YES | MUL | (I've omitted other fields from this table description, which are not of use here) SELECT id, staff_group_id FROM person where username= [username value from a PHP variable I already have]; 2. Now knowing the staff_group_id for the user, I need to find which profile fields (profile_field_id) are available to members of that staff group, from the 'profile_template' table: +------------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | position | int(11) | YES | | NULL | | | staff_group_id | int(11) | YES | MUL | NULL | | | profile_field_id | int(11) | YES | MUL | NULL | | +------------------+---------+------+-----+---------+----------------+ This would be something like: SELECT position, profile_field_id from profile_template WHERE staff_group_id = [the staff group id of my user, that I'd just already looked up] ; At this point I get stuck: I have a feeling a JOIN of some kind will be necessary, but I'm afraid that I haven't quite had a lightbulb moment regarding joins and don't fully understand them properly. Is it possible to combine the two queries above into one combined query? |
|
(I would be expecting to obtain several profile_field_id values for the particular staff group.) 3. Unfortunately, there's more. The profile_field_id above is an index into another table (profile_field) which contains what is essentially metadata about each profile field (ie, name, type, viewing order). So, for *each* profile_field_id found from above, I would need all data for (only) the profile fields that match the found ids (still with me?). profile_template.profile_field_id matches profile_field.id |
|
(profile_field table described below) +--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | content_type | varchar(10) | YES | | NULL | | | position | int(11) | NO | | 999 | | +--------------+--------------+------+-----+---------+----------------+ 4. And even more (this is the final constraint!). Having obtained the data so far, I finally need to obtain the "actual" data for the profile fields which actually apply to the specific user. These are stored in yet another table (profile_record): +--------------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | content | text | YES | | NULL | | | is_visible_on_site | int(11) | YES | | 1 | | | person_id | int(11) | YES | MUL | NULL | | | profile_field_id | int(11) | YES | MUL | NULL | | +--------------------+---------+------+-----+---------+----------------+ Here, person_id is the id of the person (as found in part 1), and profile_field_id is the id (ie, type) of the field as described in the profile_field table. (And then finally I can hopefully start assigning the data to appropriate PHP variables and start creating the output for my form..) The (large and vague) question, of course, is: How can I do it? |
|
For safety, do I need to somehow make this one atomic action? |
|
Or can I safely do this as a series of queries, with the data obtained at each stage being transferred into and out of PHP variables as appropropriate (which would be much easier, I think!) |
|
How on earth can I make such a query work? (My head's been spinning just trying to decode the database setup so far, to work out what data I need) |
#4
| ||||||
| ||||||
|
|
El 26/10/2010 17:23, David escribió/wrote: 1. I know the person's username initially, but not their id or staff_group, which I need to determine in order to subsequently find which data applies to the user (which is connected by these fields). These are obtained from the table 'person': +-------------------------------------+--------------+------+-----+ | Field | Type | Null | Key | +-------------------------------------+--------------+------+-----+ | id | int(11) | NO | PRI | | username | varchar(255) | YES | | | staff_group_id | int(11) | YES | MUL | (I've omitted other fields from this table description, which are not of use here) SELECT id, staff_group_id FROM person where username= [username value from a PHP variable I already have]; 2. Now knowing the staff_group_id for the user, I need to find which profile fields (profile_field_id) are available to members of that staff group, from the 'profile_template' table: +------------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | position | int(11) | YES | | NULL | | | staff_group_id | int(11) | YES | MUL | NULL | | | profile_field_id | int(11) | YES | MUL | NULL | | +------------------+---------+------+-----+---------+----------------+ This would be something like: SELECT position, profile_field_id from profile_template WHERE staff_group_id = [the staff group id of my user, that I'd just already looked up] ; At this point I get stuck: I have a feeling a JOIN of some kind will be necessary, but I'm afraid that I haven't quite had a lightbulb moment regarding joins and don't fully understand them properly. Your reasoning basically follows the logic of the tables joins you need to perform and in the same order ![]() |
|
1. You start with a base table (FROM) 2. You add tables with the appropriate JOIN statement: 2.1 You write the expression for the match in the ON clause 2.2 You prepend a modifier to decide what to do with rows that don't have a match: - LEFT: show all rows from the table in left - RIGHT: show all rows from the table in right - INNER: only show matching rows 3. Rows that match more than one row get duplicated to hold all matches. |
|
So your query is: SELECT pe.id AS person_id, pt.position, pt.profile_field_id FROM person pe LEFT JOIN profile_template pt ON pe.staff_group_id=pt.staff_group_id |
|
3. Unfortunately, there's more. The profile_field_id above is an index into another table (profile_field) which contains what is essentially metadata about each profile field (ie, name, type, viewing order). So, for *each* profile_field_id found from above, I would need all data for (only) the profile fields that match the found ids (still with me?). profile_template.profile_field_id matches profile_field.id (profile_field table described below) +--------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | content_type | varchar(10) | YES | | NULL | | | position | int(11) | NO | | 999 | | +--------------+--------------+------+-----+---------+----------------+ You already have it: SELECT pe.id AS person_id, pt.position AS profile_template_position, pf.name, pf.content_type, pf.position AS profile_field_position FROM person pe LEFT JOIN profile_template pt ON pe.staff_group_id=pt.staff_group_id LEFT JOIN profile_field pf ON pt.profile_field_i=pf.id |
|
4. And even more (this is the final constraint!). Having obtained the data so far, I finally need to obtain the "actual" data for the profile fields which actually apply to the specific user. These are stored in yet another table (profile_record): +--------------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | content | text | YES | | NULL | | | is_visible_on_site | int(11) | YES | | 1 | | | person_id | int(11) | YES | MUL | NULL | | | profile_field_id | int(11) | YES | MUL | NULL | | +--------------------+---------+------+-----+---------+----------------+ Here, person_id is the id of the person (as found in part 1), and profile_field_id is the id (ie, type) of the field as described in the profile_field table. Any difficulty so far? ![]() |
|
p_id | prfl_tpl_posn | pf_id | name | ctype | content | fvis | +------+---------------+-------+-----------+----------+-----------+------+ 100 | 1 | 1 | Profile 1 | longtext | | 1 | 100 | 1 | 1 | Profile 1 | longtext | | 0 | 100 | 1 | 1 | Profile 1 | longtext | | 0 | 100 | 1 | 1 | Profile 1 | longtext | Some text | 1 | 100 | 2 | 3 | Profile 3 | text | | 1 | 100 | 2 | 3 | Profile 3 | text | | 0 | 100 | 2 | 3 | Profile 3 | text | | 0 | 100 | 2 | 3 | Profile 3 | text | Some text | 1 | 100 | 3 | 2 | Profile 2 | text | | 1 | 100 | 3 | 2 | Profile 2 | text | | 0 | 100 | 3 | 2 | Profile 2 | text | | 0 | 100 | 3 | 2 | Profile 2 | text | Some text | 1 | 100 | 4 | 4 | Profile 4 | longtext | | 1 | 100 | 4 | 4 | Profile 4 | longtext | | 0 | 100 | 4 | 4 | Profile 4 | longtext | | 0 | 100 | 4 | 4 | Profile 4 | longtext | Some text | 1 | +------+---------------+-------+-----------+----------+-----------+------+ |
#5
| |||
| |||
|
|
In article <ia6rp8$lm3$1 (AT) news (DOT) eternal-september.org>, David <david (AT) 55952163-3189045 (DOT) bogus.domain.invalid> wrote: Is it possible to combine the two queries above into one combined query? Certainly. Something along these lines ought to work: SELECT position, profile_field_id FROM person INNER JOIN profile_template ON person.staff_group_id = profile_template.staff_group_id WHERE username = [username value from your PHP variable] |
|
How on earth can I make such a query work? (My head's been spinning just trying to decode the database setup so far, to work out what data I need) RTFM. :-) |
#6
| |||
| |||
|
|
My attempted query was: SELECT pers.id AS p_id, pt.position AS prfl_tpl_posn, pf.id AS pf_id, pf.name, pf.content_type AS ctype, content, pr.is_visible_on_site AS fvis FROM person pers LEFT JOIN profile_template pt ON pers.staff_group_id=pt.staff_group_id LEFT JOIN profile_field pf ON pt.profile_field_id=pf.id LEFT JOIN profile_record pr ON pers.id=pr.person_id WHERE username = 'somebody'; And this resulted in: [..the result iterating through the matching fields multiple times] |
|
p_id | prfl_tpl_posn | pf_id | name | ctype | content | fvis | +------+---------------+-------+-----------+----------+-----------+------+ 100 | 1 | 1 | Profile 1 | longtext | | 1 | 100 | 2 | 3 | Profile 3 | text | | 0 | 100 | 3 | 2 | Profile 2 | text | | 0 | 100 | 4 | 4 | Profile 4 | longtext | Some text | 1 | +------+---------------+-------+-----------+----------+-----------+------+ |
#7
| |||
| |||
|
|
On 29/10/10 11:28, David wrote: My attempted query was: SELECT pers.id AS p_id, * * pt.position AS prfl_tpl_posn, * * pf.id AS pf_id, * * pf.name, pf.content_type AS ctype, * * content, pr.is_visible_on_site AS fvis FROM person pers LEFT JOIN profile_template pt ON pers.staff_group_id=pt.staff_group_id LEFT JOIN profile_field pf ON pt.profile_field_id=pf.id LEFT JOIN profile_record pr ON pers.id=pr.person_id WHERE username = 'somebody'; And this resulted in: [..the result iterating through the matching fields multiple times] OK, after some head-scratching, I've come up with.. SELECT pers.id AS p_id, * * *pt.position AS prfl_tpl_posn, * * *pf.id AS pf_id, * * *pf.name, pf.content_type AS ctype, * * *content, pr.is_visible_on_site AS fvis FROM person pers LEFT JOIN profile_template pt ON pers.staff_group_id=pt.staff_group_id LEFT JOIN profile_field pf ON pt.profile_field_id=pf.id LEFT JOIN profile_record pr ON pers.id=pr.person_id AND pf.id=pr.profile_field_id WHERE username = 'somebody'; Adding an AND clause to the join (to match up on the profile_field_id's as well) seems to have done the trick, I'm just not certain whether that's the right thing, or whether I just happen to have got the intended result (this time) by chance..? (Not a good thing!) +------+---------------+-------+-----------+----------+-----------+------+ | p_id | prfl_tpl_posn | pf_id | name * * *| ctype * *| content* | fvis | +------+---------------+-------+-----------+----------+-----------+------+ | *100 | * * * * * * 1 | * * 1 | Profile 1 | longtext |* * * * * | * *1 | | *100 | * * * * * * 2 | * * 3 | Profile 3 | text * * | * * * * * | * *0 | | *100 | * * * * * * 3 | * * 2 | Profile 2 | text * * | * * * * * | * *0 | | *100 | * * * * * * 4 | * * 4 | Profile 4 | longtext |Some text | * *1 | +------+---------------+-------+-----------+----------+-----------+------+ If this is the right solution, should I really ought to have brackets around the whole ON clause? (I'm not sure how SQL does its parsing order) Hmm, I'm afraid I clearly really need to find a tutorial or book that explains JOINs to me in a way that I can clearly visualise and understand... David. |
#8
| |||
| |||
|
| On 29/10/10 11:28, David wrote: My attempted query was: SELECT pers.id AS p_id, pt.position AS prfl_tpl_posn, pf.id AS pf_id, pf.name, pf.content_type AS ctype, content, pr.is_visible_on_site AS fvis FROM person pers LEFT JOIN profile_template pt ON pers.staff_group_id=pt.staff_group_id LEFT JOIN profile_field pf ON pt.profile_field_id=pf.id LEFT JOIN profile_record pr ON pers.id=pr.person_id WHERE username = 'somebody'; And this resulted in: [..the result iterating through the matching fields multiple times] OK, after some head-scratching, I've come up with.. SELECT pers.id AS p_id, pt.position AS prfl_tpl_posn, pf.id AS pf_id, pf.name, pf.content_type AS ctype, content, pr.is_visible_on_site AS fvis FROM person pers LEFT JOIN profile_template pt ON pers.staff_group_id=pt.staff_group_id LEFT JOIN profile_field pf ON pt.profile_field_id=pf.id LEFT JOIN profile_record pr ON pers.id=pr.person_id AND pf.id=pr.profile_field_id WHERE username = 'somebody'; Adding an AND clause to the join (to match up on the profile_field_id's as well) seems to have done the trick, I'm just not certain whether that's the right thing, or whether I just happen to have got the intended result (this time) by chance..? (Not a good thing!) +------+---------------+-------+-----------+----------+-----------+------+ | p_id | prfl_tpl_posn | pf_id | name | ctype | content | fvis | +------+---------------+-------+-----------+----------+-----------+------+ | 100 | 1 | 1 | Profile 1 | longtext | | 1 | | 100 | 2 | 3 | Profile 3 | text | | 0 | | 100 | 3 | 2 | Profile 2 | text | | 0 | | 100 | 4 | 4 | Profile 4 | longtext | Some text | 1 | +------+---------------+-------+-----------+----------+-----------+------+ |
|
If this is the right solution, should I really ought to have brackets around the whole ON clause? (I'm not sure how SQL does its parsing order) |
|
Hmm, I'm afraid I clearly really need to find a tutorial or book that explains JOINs to me in a way that I can clearly visualise and understand... |
#9
| |||
| |||
|
|
This may help: |
#10
| |||||
| |||||
|
|
El 29/10/2010 15:36, David escribió/wrote: OK, after some head-scratching, I've come up with.. SELECT pers.id AS p_id, pt.position AS prfl_tpl_posn, pf.id AS pf_id, pf.name, pf.content_type AS ctype, content, pr.is_visible_on_site AS fvis FROM person pers LEFT JOIN profile_template pt ON pers.staff_group_id=pt.staff_group_id LEFT JOIN profile_field pf ON pt.profile_field_id=pf.id LEFT JOIN profile_record pr ON pers.id=pr.person_id AND pf.id=pr.profile_field_id WHERE username = 'somebody'; |
|
The JOIN clause basically accepts any expression that's valid in a WHERE clause so there's nothing weird in adding an AND if the join requires a match in more than one column. |
|
Each join you add refines the result of the previous set of joins. |
|
If this is the right solution, should I really ought to have brackets around the whole ON clause? (I'm not sure how SQL does its parsing order) I see no purpose in that. Operator precedence can hardly be an issue when the only alternative is a syntax error: SELECT * FROM left_table a INNER JOIN right_table b (ON a.foo=b.foo) AND a.bar=b.bar |
|
Hmm, I'm afraid I clearly really need to find a tutorial or book that explains JOINs to me in a way that I can clearly visualise and understand... This may help: http://www.codinghorror.com/blog/200...sql-joins.html |
![]() |
| Thread Tools | |
| Display Modes | |
| |