141 lines
3.7 KiB
PHP
141 lines
3.7 KiB
PHP
<?php namespace Laravel\Database\Query\Grammars;
|
|
|
|
use Laravel\Database\Query;
|
|
|
|
class SQLServer extends Grammar {
|
|
|
|
/**
|
|
* The keyword identifier for the database system.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $wrapper = '[%s]';
|
|
|
|
/**
|
|
* Compile a SQL SELECT statement from a Query instance.
|
|
*
|
|
* @param Query $query
|
|
* @return string
|
|
*/
|
|
public function select(Query $query)
|
|
{
|
|
$sql = parent::components($query);
|
|
|
|
// SQL Server does not currently implement an "OFFSET" type keyword, so we
|
|
// actually have to generate the ANSI standard SQL for doing offset like
|
|
// functionality. In the next version of SQL Server, an OFFSET like
|
|
// keyword is included for convenience.
|
|
if ($query->offset > 0)
|
|
{
|
|
return $this->ansi_offset($query, $sql);
|
|
}
|
|
|
|
// Once all of the clauses have been compiled, we can join them all as
|
|
// one statement. Any segments that are null or an empty string will
|
|
// be removed from the array of clauses before they are imploded.
|
|
return $this->concatenate($sql);
|
|
}
|
|
|
|
/**
|
|
* Compile the SELECT clause for a query.
|
|
*
|
|
* @param Query $query
|
|
* @return string
|
|
*/
|
|
protected function selects(Query $query)
|
|
{
|
|
if ( ! is_null($query->aggregate)) return;
|
|
|
|
$select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
|
|
|
|
// Instead of using a "LIMIT" keyword, SQL Server uses the "TOP"
|
|
// keyword within the SELECT statement. So, if we have a limit,
|
|
// we will add it here.
|
|
//
|
|
// We will not add the TOP clause if there is an offset however,
|
|
// since we will have to handle offsets using the ANSI syntax
|
|
// and will need to remove the TOP clause in that situation.
|
|
if ($query->limit > 0 and $query->offset <= 0)
|
|
{
|
|
$select .= 'TOP '.$query->limit.' ';
|
|
}
|
|
|
|
return $select.$this->columnize($query->selects);
|
|
}
|
|
|
|
/**
|
|
* Generate the ANSI standard SQL for an offset clause.
|
|
*
|
|
* @param Query $query
|
|
* @param array $components
|
|
* @return array
|
|
*/
|
|
protected function ansi_offset(Query $query, $components)
|
|
{
|
|
// An ORDER BY clause is required to make this offset query
|
|
// work, so if one doesn't exist, we'll just create a dummy
|
|
// clause to satisfy the database.
|
|
if ( ! isset($components['orderings']))
|
|
{
|
|
$components['orderings'] = 'ORDER BY (SELECT 0)';
|
|
}
|
|
|
|
// We need to add the row number to the query results so we
|
|
// can compare it against the offset and limit values given
|
|
// for the statement. To do that we'll add an expression to
|
|
// the select statement for the row number.
|
|
$orderings = $components['orderings'];
|
|
|
|
$components['selects'] .= ", ROW_NUMBER() OVER ({$orderings}) AS RowNum";
|
|
|
|
unset($components['orderings']);
|
|
|
|
$start = $query->offset + 1;
|
|
|
|
// Next we need to calculate the constraint that should be
|
|
// placed on the row number to get the correct offset and
|
|
// limit on the query. If a limit has not been set, we'll
|
|
// only add a constraint to handle offset.
|
|
if ($query->limit > 0)
|
|
{
|
|
$finish = $query->offset + $query->limit;
|
|
|
|
$constraint = "BETWEEN {$start} AND {$finish}";
|
|
}
|
|
else
|
|
{
|
|
$constraint = ">= {$start}";
|
|
}
|
|
|
|
// Now, we're finally ready to build the final SQL query.
|
|
// We'll create a common table expression with the query
|
|
// and then select all of the results from it where the
|
|
// row number is between oru given limit and offset.
|
|
$sql = $this->concatenate($components);
|
|
|
|
return "SELECT * FROM ($sql) AS TempTable WHERE RowNum {$constraint}";
|
|
}
|
|
|
|
/**
|
|
* Compile the LIMIT clause for a query.
|
|
*
|
|
* @param Query $query
|
|
* @return string
|
|
*/
|
|
protected function limit(Query $query)
|
|
{
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Compile the OFFSET clause for a query.
|
|
*
|
|
* @param Query $query
|
|
* @return string
|
|
*/
|
|
protected function offset(Query $query)
|
|
{
|
|
return '';
|
|
}
|
|
|
|
} |