Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am trying to sort by modification date descending (meaning latest first) within a multi-dimensional array with the condition that status = 0 (unrated image) and status != 1 (rated image).

Is it possible to sort the array so that the top 2 would be following the logic below:

If (there are multiple versions of an image)
   If (there is a version that has been rated)
      If (there is a new unrated version of the image)
         Display (the most recent version that has a rating) and 
         (the most recent unrated version) as top 2 of array
      Else
         Display (the most recent version that has a rating) as top 1
   Else
      Display (the most recent unrated version) as top 1
Else
   Display (the only version) as top 1

Here's my UPDATED PHP code below (UPDATED 9/6/2013):

updateImageDisplayStatus($caseID,$patientID);

function updateImageDisplayStatus($caseid,$patientid) {

$connection = getMySqlConnection();
$sql = "SELECT image_name FROM images WHERE patientid = '{$patientid}' AND caseid = '{$caseid}' ";

$imageGroup = array();
$result = mysql_query($sql,$connection);
while($row = mysql_fetch_assoc($result)) {

    $fileName =  $row['image_name'];
    $tmpName = $row['image_name'];
    list($leftN,$rightN) = explode($caseid."_",$tmpName);
    //$spltName = explode('_',$rightN);
    $shortFileName = $rightN;
    list($noExtensionFileName,$extension) = explode('.',$shortFileName);
    //$extension = '.nii.gz';
    list($groupName,$appendDate) = explode('_',$noExtensionFileName);
    // echo $groupName = just the original name.

  $sql_2 = "SELECT image1.image_name as i1_image_name
  ,image1.comments   as i1_comments
  ,image1.status     as i1_status
  ,image1.mod_date   as i1_mod_date
  ,image2.image_name as i2_image_name
  ,image2.comments   as i2_comments
  ,image2.status     as i2_status
  ,image2.mod_date   as i2_mod_date
  FROM (SELECT CASE WHEN status = 0 THEN 1 ELSE 0 END as rated
          ,image_name
          ,comments
          ,status
          ,mod_date
      FROM images
     WHERE image_name like '%{$groupName}%' 
     ORDER BY 1 ASC, mod_date DESC
     LIMIT 1
   ) image1
  LEFT OUTER
  JOIN images image2
    ON image1.status > 0
   AND image2.status = 0
   AND image2.mod_date > image1.mod_date
   AND image2.image_name like '%{$groupName}%'
      AND patientid = '{$patientid}' AND caseid = '{$caseid}'
 ORDER BY image2.mod_date DESC
 LIMIT 1";

$result_2 = mysql_query($sql_2,$connection);
if($row = mysql_fetch_assoc($result_2)) {
    $imageGroup[$groupName]   = array();
    $imageGroup[$groupName][] = array(
        'image_name'  => $row['i1_image_name'],
        'comments'    => $row['i1_comments'], 
        'status'      => $row['i1_status'],
        'mod_date'    => $row['i1_mod_date']
        );
    if ( !empty( $row['i2_image_name'] ) ) {
        $imageGroup[$groupName][] = array(
            'image_name'  => $row['i2_image_name'],
            'comments'    => $row['i2_comments'], 
            'status'      => $row['i2_status'],
            'mod_date'    => $row['i2_mod_date']
        );
    }
}
echo "Group $groupName:<br />";
echo "Size of Group:".sizeof($imageGroup[$groupName]).'<br />';

echo $imageGroup[$groupName][0]['image_name'].'<br />';
echo $imageGroup[$groupName][1]['image_name'].'<br />';
}
}

UPDATE:

Thanks to @gwc for the suggestion to let SQL do the work. I forgot to add that the 1-2 images that are searched and sorted have to be within the specified $caseid and $patientid. As a result, the first sql statement should be: $sql = "SELECT image_name FROM images WHERE patientid = '{$patientid}' AND caseid = '{$caseid}' ";

share|improve this question
 
There is no reason at all to do this in PHP with a large number of MySQL queries. Just do it in MySQL. It would be much easier to give you a good SQL query to work with if you provide the table structure (with sample data) as well as the desired output that you want. –  Mike Brant Sep 5 at 22:50

2 Answers

up vote 1 down vote accepted

Updated SQL to limit to within the same patient and case

If I understand your problem correctly, you could let SQL do the work for you. No loops or arrays required. The following SQL should return a single row. Unfortunately, I don't have a way to test this at the moment so I hope there are no errors in the SQL. This SQL would replace your $sql_2:

SELECT image1.patientid
      ,image1.caseid
      ,image1.image_name as i1_image_name
      ,image1.comments   as i1_comments
      ,image1.status     as i1_status
      ,image1.mod_date   as i1_mod_date
      ,image2.image_name as i2_image_name
      ,image2.comments   as i2_comments
      ,image2.status     as i2_status
      ,image2.mod_date   as i2_mod_date
  FROM (SELECT CASE WHEN status = 0 THEN 1 ELSE 0 END as rated
              ,patientid
              ,caseid
              ,image_name
              ,comments
              ,status
              ,mod_date
          FROM images
         WHERE patientid  = '{$patientid}'
           AND caseid     = '{$caseid}'
           AND image_name like '%{$group_name}%'
         ORDER BY 1 ASC, mod_date DESC
         LIMIT 1
       ) image1
  LEFT OUTER
  JOIN images image2
    ON image1.status     > 0
   AND image2.patientid  = image1.patientid
   AND image2.caseid     = image1.caseid
   AND image2.status     = 0
   AND image2.mod_date   > image1.mod_date
   AND image2.image_name like '%{$group_name}%'
 ORDER BY image2.mod_date DESC
 LIMIT 1

The returned row contains 10 columns:

  • patientid
  • caseid
  • i1_image_name
  • i1_comments
  • i1_status
  • i1_mod_date
  • i2_image_name
  • i2_comments
  • i2_status
  • i2_mod_date

The i1_* columns are from the first image and the i2_* columns are from the second image (if there is one). If there is a rated image, i1_* will represent the most recently modified rated image and i2_* will represent the most recently modified unrated image that was modified after the i1_* image. If there are not unrated images that were modified after the rated image then i2_* will be NULL. If there are no rated images, then i1_* will represent the most recently modified unrated image and i2_* will be NULL.

Updated

Here's how I see it being used.

    $sql_2 = "SELECT image1.patientid
      ,image1.caseid
      ,image1.image_name as i1_image_name
      ,image1.comments   as i1_comments
      ,image1.status     as i1_status
      ,image1.mod_date   as i1_mod_date
      ,image2.image_name as i2_image_name
      ,image2.comments   as i2_comments
      ,image2.status     as i2_status
      ,image2.mod_date   as i2_mod_date
  FROM (SELECT CASE WHEN status = 0 THEN 1 ELSE 0 END as rated
              ,patientid
              ,caseid
              ,image_name
              ,comments
              ,status
              ,mod_date
          FROM images
         WHERE image_name like '%{$group_name}%'
         ORDER BY 1 ASC, mod_date DESC
         LIMIT 1
       ) image1
  LEFT OUTER
  JOIN images image2
    ON image1.status > 0
   AND image2.patientid  = image1.patientid
   AND image2.caseid     = image1.caseid
   AND image2.status     = 0
   AND image2.mod_date   > image1.mod_date
   AND image2.image_name like '%{$group_name}%'
 ORDER BY image2.mod_date DESC
 LIMIT 1";

    $result_2 = mysql_query($sql_2,$connection);
    if($row = mysql_fetch_assoc($result_2)) {
        $imageGroup[$groupName]   = array();
        $imageGroup[$groupName][] = array(
            'image_name'  => $row['i1_image_name'],
            'comments'    => $row['i1_comments'], 
            'status'      => $row['i1_status'],
            'mod_date'    => $row['i1_mod_date']
            );
        if ( !empty( $row['i2_image_name'] ) ) {
            $imageGroup[$groupName][] = array(
                'image_name'  => $row['i2_image_name'],
                'comments'    => $row['i2_comments'], 
                'status'      => $row['i2_status'],
                'mod_date'    => $row['i2_mod_date']
            );
        }
    }

replaces:

if (!isset($imageGroup[$groupName]) {   
    $imageGroup[$groupName] = array();

    $sql_2 = "SELECT * FROM images WHERE image_name like '%".$groupName."%'";
    $result_2 = mysql_query($sql_2,$connection);
    while($row - mysql_fetch_assoc($result_2)) {
        $imageGroup[$groupName][] = array( // sort each field as 
            'image_name' => $row['image_name'],
            'comments' => $row['comments'], 
            'status' => $row['status'], // determines whether image is rated or unrated
            'mod_date' => $row['mod_date'] // the date we need to compare
            );
    }
}
else {
    for ($i=0; $i <sizeof($imageGroup[$groupName]); $i++) {
        if ($imageGroup[$groupName][$i]['status'] == 0) {
        // compare??    

        }
        if ($imageGroup[$groupName][$i]['status'] !== 0) {
        // compare??    

        }


    }
}

upon completion, $imageGroup[$groupName] will contain an array with either one or two elements.

Hope this is on target. :)

share|improve this answer
 
This is really helpful! I tested it and worked as advertised but I forgot to add that these images are divided by two specific ids -caseid and personid. (see original post for update). I tried to add the WHERE statement to your existing sql statement but it does not seem to work. Your original sql statement identifies the two images rated and unrated but they are for different case. I need to specify so that these conditions apply when the two related images are within the same case. –  alchuang Sep 6 at 16:38
 
Easy fix. Updated SQL to limit second image be within the same patient and case. –  gwc Sep 6 at 22:04

Here's an old bit of code you can use:

class ProductHelper {

// sort products by name
static function sort_name_asc($a,$b) {
    return strcmp($a['name'],$b['name']);
}
static function sort_name_desc($a,$b) {
    return strcmp($b['name'],$a['name']);
}
// sort products by price
static function sort_price_asc($a,$b) {
    return $a['price'] > $b['price'];
}
static function sort_price_desc($a,$b) {
    return $a['price'] < $b['price'];
}
// sort products by last update
static function sort_date_asc($a,$b) {
    return $a['created'] > $b['created'];
}
static function sort_date_desc($a,$b) {
    return $a['created'] < $b['created'];
}
// sort array by sort_order
static function sort_sort_order($a,$b) {
    return $a['sort_order'] > $b['sort_order'];
}

    function sortProducts($products, $sortMode) {
        if (!is_array($products)) return null;
        usort($products, 'ProductHelper::sort_'.$sortMode);
        return $products;
    }

}

Example use:

$ProductHelper = new ProductHelper();
$ProductHelper->sortProducts($array_of_products, "date_desc");
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.