Skip to content

Commit

Permalink
Implementing DISTINCT ON for SQLServer
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzo committed Mar 7, 2015
1 parent 58ffc08 commit 1325d41
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
53 changes: 52 additions & 1 deletion src/Database/Dialect/SqlserverDialectTrait.php
Expand Up @@ -72,7 +72,7 @@ protected function _selectQueryTranslator($query)
return $this->_pagingSubquery($query, $limit, $offset);
}

return $query;
return $this->_transformDistinct($query);
}

/**
Expand Down Expand Up @@ -131,6 +131,57 @@ protected function _pagingSubquery($original, $limit, $offset)
return $outer;
}

/**
* Returns the passed query after rewriting the DISTINCT clause, so that drivers
* that do not support the "ON" part can provide the actual way it should be done
*
* @param Query $original The query to be transformed
* @return Query
*/
protected function _transformDistinct($original)
{
if (!is_array($original->clause('distinct'))) {
return $original;
}

$query = clone $original;
$distinct = $query->clause('distinct');
$query->distinct(false);

$order = new OrderByExpression($distinct);
$query
->select(function ($q) use ($distinct, $order) {
$over = $q->newExpr('ROW_NUMBER() OVER')
->add('(PARTITION BY')
->add($q->newExpr()->add($distinct)->type(','))
->add($order)
->add(')')
->type(' ');
return [
'_cake_distinct_pivot_' => $over
];
})
->limit(null)
->offset(null)
->order([], true);

$outer = new Query($query->connection());
$outer->select('*')
->from(['_cake_distinct_' => $query])
->where(['_cake_distinct_pivot_' => 1]);

// Decorate the original query as that is what the
// end developer will be calling execute() on originally.
$original->decorateResults(function ($row) {
if (isset($row['_cake_distinct_pivot_'])) {
unset($row['_cake_distinct_pivot_']);
}
return $row;
});

return $outer;
}

/**
* Returns a dictionary of expressions to be transformed when compiling a Query
* to SQL. Array keys are method names to be called in this class
Expand Down
5 changes: 5 additions & 0 deletions tests/TestCase/Database/QueryTest.php
Expand Up @@ -1479,6 +1479,11 @@ public function testSelectDistinctON()
->from(['a' => 'articles'])
->execute();
$this->assertCount(2, $result);
$expected = [
['id' => 1, 'author_id' => 1],
['id' => 2, 'author_id' => 3],
];
$this->assertEquals($expected, $result->fetchAll('assoc'));
}

/**
Expand Down

0 comments on commit 1325d41

Please sign in to comment.