简体   繁体   中英

Trouble understanding how to JOIN mySQL tables properly

Ok here is my problem. I'm adding a table to a existing database to store project notes.

"worklog" is the table with the projects "worklognotes" is the table with the project notes

The notes will be displayed like a discussion thread. worklognotes columns are set up like this id, worklog_id, timestamp, notes.

"id" is the table Unique id. "worklog_id" is the id of the project the note is pretaining to that is stored in another table. "timestamp" is well a Timestamp "notes" are the actual ongoing notes about the project. There could be many notes to a single project.

Looking at the database query below. I have joined the two queries "It's my first join so I'm not sure I've done it right." It is reading the information in both tables and displaying it. But the below code is displaying every entry in "worklog" that has a record in the "worklognotes" table. I need it to display one entry from "worklog" and many notes from "worklognotes"

Can you help or suggest a direction?

$connection = mysql_connect ("localhost", "user", "pass") or die ("I cannot connect to the database.");
$db = mysql_select_db ("database", $connection) or die (mysql_error());

$query = "SELECT * FROM worklog ";  
$query .= "JOIN worklognotes ON worklog_id = worklognotes.worklog_id ";  
$query .= "WHERE worklognotes.worklog_id=worklog.id ORDER BY worklognotes.id DESC";

Your query to create the JOIN looks correct, but your where clause is redundant. Try this:

SELECT *
FROM worklog
JOIN worklognotes ON worklog_id = worklognotes.worklog_id
ORDER BY worklognotes.id DESC

However for your specific requirements (fetching one record from one table and multiple records from another) there doesn't seem to be a need to join. I think it is best to run two separate queries, otherwise you will get all the data from the first table repeated in every row in your result set.

You'd most likely want:

SELECT *
FROM worklog
LEFT JOIN worklognotes ON worklog_id = worklognotes.worklog_id
WHERE worklog_id = $worklog_id
ORDER BY worklognotes.timestamp DESC;

This will pull out only the work log which has the id stored in $worklog_id (say, 57), and any/all associated worklog notes, displayed newest first.

You query was pulling out ALL worklogs and ALL worklognotes, since you didn't specify exactly which worklog you want, just that they had to have a worklognote.

That is how a join works. You will get one row for each valid combination. The closest you can get to what you want is agregating all worknotes.

SELECT workitem.workID, GROUP_CONCAT( worknotes.note ) 
FROM  `workitem` 
JOIN worknotes ON worknotes.workID = workitem.workID
GROUP BY workID

This will give you just one row per workitem and all notes concatinated and seperated with ,

Depending on your column names you may be able to simplify you query with a ntural join:

SELECT workID, GROUP_CONCAT( worknotes.note ) 
FROM  `workitem` 
NATURAL JOIN  worknotes
GROUP BY `workID`

Natural join is not standart sql but it is a very handy tool. If there is EXACTLY ONE colum that the two tables have in common it will join them just as a inner join with a where clause.

If you want to use another seperator:

SELECT workID, GROUP_CONCAT( worknotes.note SEPARATOR '; ') 
    FROM  `workitem` 
    NATURAL JOIN  worknotes
    GROUP BY `workID`

Details on GROUP_CONCAT:

http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

Looking at the database query below. I have joined the two queries "It's my first join so I'm not sure I've done it right." It is reading the information in both tables and displaying it. But the below code is displaying every entry in "worklog" that has a record in the "worklognotes" table. I need it to display one entry from "worklog" and many notes from "worklognotes"

Yes, thats how it works when you join. Youre going to get the worklog entry and a worklognotes entry as a single row. This means youre going to have the same worklog entry multiple times unless it only has one worklognote. You need to sort this out on the php side if you want display in some kind of hierarchy.

So if you want all worklogs (or more than jsut one really) and their notes you would use the query you have and then iterate over the results to organize then appropriately for example assume $result is your mysql_result resource and $worklog_columns and $worklognote_columns contain an array of the columns names for each table in the format 'column_name' => null then you might do something like the following:

$worklog = array();

while(false !== ($record = mysql_fetch_assoc($result))){
  // get only the data for a worklognote
  $note = array(array_intersect_key($result, $worklognote_columns)); 

  // get the primary key of the worklog
  $id = $record['worklog_id'];


  if(!isset($worklog[$id])){
    // if we havent already processed this worklog form a previous row

    // get the work log data in a separate array
    $log = array_intersect_key($result, $worklog_columns);

    // add a notes key which will hold an array of worklog_notes
    // and assifn the note joined to this row as the first note
    $log['notes'] = array($note);
  }
  else
  {
     // otherwise jsut append the not joined to this row
     // to the existing worklog we processed
     $worklog[$id]['notes'][] = $note;
  }
}

However the thing you have to be aware of is that if the two tables youre joining have columns with the same name, then if you use MYSQL_ASSOC you will only get the value from the column on the joined table, not from both. IF you need access to the value on both tables then you either need to use MYSQL_NUM or MYSQL_BOTH or alias every column in your query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM