-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Description
Affected Function
on yii2/db/mssql/QueryBuilder.php
:
/**
* Builds the ORDER BY/LIMIT/OFFSET clauses for SQL SERVER 2012 or newer.
* @param string $sql the existing SQL (without ORDER BY/LIMIT/OFFSET)
* @param array $orderBy the order by columns. See [[\yii\db\Query::orderBy]] for more details on how to specify this parameter.
* @param int $limit the limit number. See [[\yii\db\Query::limit]] for more details.
* @param int $offset the offset number. See [[\yii\db\Query::offset]] for more details.
* @return string the SQL completed with ORDER BY/LIMIT/OFFSET (if any)
*/
protected function newBuildOrderByAndLimit($sql, $orderBy, $limit, $offset)
{
$orderBy = $this->buildOrderBy($orderBy);
if ($orderBy === '') {
// ORDER BY clause is required when FETCH and OFFSET are in the SQL
$orderBy = 'ORDER BY (SELECT NULL)';
}
$sql .= $this->separator . $orderBy;
// [https://technet.microsoft.com/en-us/library/gg699618.aspx]
$offset = $this->hasOffset($offset) ? $offset : '0';
$sql .= $this->separator . "OFFSET $offset ROWS";
if ($this->hasLimit($limit)) {
$sql .= $this->separator . "FETCH NEXT $limit ROWS ONLY";
}
return $sql;
}
Problem Description
When generating paginated queries using SQL Server 2012+ and the original SQL contains SELECT DISTINCT
, the current fallback ORDER BY (SELECT NULL)
fails with:
SQLSTATE[42000]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
Example query generated:
SELECT DISTINCT * FROM [EmpleadoNomina] WHERE [UltimaActividadEmpleado]=-1 ORDER BY (SELECT NULL) OFFSET 0 ROWS FETCH NEXT 12 ROWS ONLY
This fails because SQL Server does not accept an ORDER BY expression that isn’t in the SELECT list when using DISTINCT
.[11][12]
Suggested Solution
Instead of ORDER BY (SELECT NULL)
, use:
ORDER BY 1
This safely orders by the first column in the SELECT list and works with SELECT DISTINCT
, allowing OFFSET/FETCH to operate without requiring knowledge of specific columns. This is a widely used pattern for generic paging in SQL Server.[12][11]
Proposed Change
Replace:
$orderBy = 'ORDER BY (SELECT NULL)';
With:
$orderBy = 'ORDER BY 1';
Additional Context
Using ORDER BY 1
is not semantically ideal but is required in cases where column names are unavailable, especially with SELECT DISTINCT
. This adjustment fixes the SQL generation and resolves the SQL Server error.