Search code examples
phpmysqlsortingsql-order-byresultset

Sort MySQL result set by nullable column with nulls first, then another column


I am creating a "Pinned" feature for my forum and I am looking for a way to put my pinned topics at the beginning of the array so that they are "stuck" to the top of the page.

If the topic is not pinned then topic_pinned=NULL if it is pinned then topic_pinned=0.

The array is sorted by topic_updated. The pinned topics need to stay sorted by topic_updated while staying at the top of the page, and then under the pinned topics are the non-pinned topics, which are also sorted by topic_updated.

Topic Array ($forum_topic_results):

Array
(
    [0] => Array
        (
            [topic_id] => 4
            [topic_subject] => Test Subject #4
            [topic_date] => 2015-09-10 18:34:18
            [topic_by] => 1
            [topic_pinned] => 
            [topic_updated] => 2015-09-10 20:37:22
        )

    [1] => Array
        (
            [topic_id] => 3
            [topic_subject] => Test Subject #3
            [topic_date] => 2015-08-22 09:24:40
            [topic_by] => 1
            [topic_pinned] => 0
            [topic_updated] => 2015-09-04 22:02:31
        )

    [2] => Array
        (
            [topic_id] => 2
            [topic_subject] => Test Subject #2
            [topic_date] => 2015-08-15 10:56:00
            [topic_by] => 1
            [topic_pinned] => 
            [topic_updated] => 2015-09-04 19:45:32
        )

    [3] => Array
        (
            [topic_id] => 1
            [topic_subject] => Test Subject #1
            [topic_date] => 2015-08-30 19:48:17
            [topic_by] => 1
            [topic_pinned] => 0
            [topic_updated] => 2015-09-03 00:44:38
        )
)

PHP:

/**
 * getAllTopics
 *
 * Retreives the topics of the chosen category from the `forum_topics` table.
 *
 * @param   $cat_id
 * @access  public
 */
public function getAllTopics($cat_id=NULL)
{
    $database=$this->database;

    $database->query('SELECT topic_id, topic_subject, topic_date, topic_by, topic_pinned, topic_locked FROM forum_topics WHERE topic_cat = :catid ORDER BY topic_updated DESC', array(':catid' => $cat_id));
    $result = $database->statement->fetchAll(PDO::FETCH_ASSOC);

    return $result;
}

# Get topics
$forum_topic_results = $this->getAllTopics($_GET['cat']);
foreach($forum_topic_results as $forum_topic_row)
{
    # Get user's username.
    $topic_by=SearchUser($forum_topic_row['topic_by']);

    $data.='<tr>'.
        '<td>'.
            '<h3><a href="'.$_SERVER['PHP_SELF'].'?action=forum_posts&topic='.$forum_topic_row['topic_id'].'">'.$forum_topic_row['topic_subject'].'</a></h3>'.
            'by '.$topic_by['username'].' on '.date('D M d, Y g:i a', strtotime($forum_topic_row['topic_date'])).
        '</td>'.
    '</tr>';
}

Outcome I want:

Array
(
    [0] => Array
        (
            [topic_id] => 3
            [topic_subject] => Test Subject #3
            [topic_date] => 2015-08-22 09:24:40
            [topic_by] => 1
            [topic_pinned] => 0
            [topic_updated] => 2015-09-04 22:02:31
        )

    [1] => Array
        (
            [topic_id] => 1
            [topic_subject] => Test Subject #1
            [topic_date] => 2015-08-30 19:48:17
            [topic_by] => 1
            [topic_pinned] => 0
            [topic_updated] => 2015-09-03 00:44:38
        )

    [2] => Array
        (
            [topic_id] => 4
            [topic_subject] => Test Subject #4
            [topic_date] => 2015-09-10 18:34:18
            [topic_by] => 1
            [topic_pinned] => 
            [topic_updated] => 2015-09-10 20:37:22
        )

    [3] => Array
        (
            [topic_id] => 2
            [topic_subject] => Test Subject #2
            [topic_date] => 2015-08-15 10:56:00
            [topic_by] => 1
            [topic_pinned] => 
            [topic_updated] => 2015-09-04 19:45:32
        )
)

Solution

  • Do antother way.

    Mark in your database table PINNED as 1.

    NOT PINNED as 0.

    After that just add (replace ORDER BY) to your query where u select topics:

    ORDER BY `topic_pinned` DESC, `topic_updated` DESC