> YII 类库手册 > CMssqlCommandBuilder
system.db.schema.mssql
继承 class CMssqlCommandBuilder » CDbCommandBuilder » CComponent
版本 $Id: CMssqlCommandBuilder.php 3515 2011-12-28 12:29:24Z mDOMba $
源码
CMssqlCommandBuilder提供为MSSQL数据表创建查询语句的基本方法。

公共属性

属性 类型 描述 定义在
dbConnection CDbConnection database connection. CDbCommandBuilder
schema CDbSchema the schema for this command builder. CDbCommandBuilder

公共方法

方法 描述 定义在
__call() 如果类中没有调的方法名,则调用这个方法。 CComponent
__construct() CDbCommandBuilder
__get() 返回一个属性值、一个事件处理程序列表或一个行为名称。 CComponent
__isset() 检查一个属性是否为null。 CComponent
__set() 设置一个组件的属性值。 CComponent
__unset() 设置一个组件的属性为null。 CComponent
applyCondition() Alters the SQL to apply WHERE clause. CDbCommandBuilder
applyGroup() Alters the SQL to apply GROUP BY. CDbCommandBuilder
applyHaving() Alters the SQL to apply HAVING. CDbCommandBuilder
applyJoin() Alters the SQL to apply JOIN clause. CDbCommandBuilder
applyLimit() This is a port from Prado Framework. CMssqlCommandBuilder
applyOrder() Alters the SQL to apply ORDER BY. CDbCommandBuilder
asa() 返回这个名字的行为对象。 CComponent
attachBehavior() 附加一个行为到组件。 CComponent
attachBehaviors() 附加一个行为列表到组件。 CComponent
attachEventHandler() 为事件附加一个事件处理程序。 CComponent
bindValues() Binds parameter values for an SQL command. CDbCommandBuilder
canGetProperty() 确定属性是否可读。 CComponent
canSetProperty() 确定属性是否可写。 CComponent
createColumnCriteria() Creates a query criteria with the specified column values. CDbCommandBuilder
createCountCommand() 为一个表创建COUNT(*)语句。 CMssqlCommandBuilder
createCriteria() Creates a query criteria. CDbCommandBuilder
createDeleteCommand() 创建DELETE语句。 CMssqlCommandBuilder
createFindCommand() 为一个表创建SELECT语句。 CMssqlCommandBuilder
createInCondition() Generates the expression for selecting rows of specified primary key values. CDbCommandBuilder
createInsertCommand() Creates an INSERT command. CDbCommandBuilder
createPkCondition() Generates the expression for selecting rows of specified primary key values. CDbCommandBuilder
createPkCriteria() Creates a query criteria with the specified primary key. CDbCommandBuilder
createSearchCondition() Generates the expression for searching the specified keywords within a list of columns. CDbCommandBuilder
createSqlCommand() Creates a command based on a given SQL statement. CDbCommandBuilder
createUpdateCommand() 创建UPDATE语句。 CMssqlCommandBuilder
createUpdateCounterCommand() 创建递增或递减特定列的UPDATE语句。 CMssqlCommandBuilder
detachBehavior() 从组件中分离一个行为。 CComponent
detachBehaviors() 从组件中分离所有行为。 CComponent
detachEventHandler() 分离一个存在的事件处理程序。 CComponent
disableBehavior() 禁用一个附加行为。 CComponent
disableBehaviors() 禁用组件附加的所有行为。 CComponent
enableBehavior() 启用一个附加行为。 CComponent
enableBehaviors() 启用组件附加的所有行为。 CComponent
evaLuateExpression() 计算一个PHP表达式,或根据组件上下文执行回调。 CComponent
getDbConnection() 返回database connection. CDbCommandBuilder
getEventHandlers() 返回一个事件的附加处理程序列表。 CComponent
getLastInsertID() Returns the last insertion ID for the specified table. CDbCommandBuilder
getSchema() 返回the schema for this command builder. CDbCommandBuilder
hasEvent() 确定一个事件是否定义。 CComponent
hasEventHandler() 检查事件是否有附加的处理程序。 CComponent
hasProperty() 确定属性是否被定义。 CComponent
raiseEvent() 发起一个事件。 CComponent

受保护方法

方法 描述 定义在
checkCriteria() 检查使用offset或limit的查询条件是否有order by子句。 CMssqlCommandBuilder
createCompositeInCondition() 生成根据指定符合键值选择行的表达式。 CMssqlCommandBuilder
ensureTable() Checks if the parameter is a valid table schema. CDbCommandBuilder
findOrdering() 基于简化语法:Http://msdn2.microsoft.com/en-us/library/aa259187(SQL.80).aspx CMssqlCommandBuilder
joinOrdering() CMssqlCommandBuilder
reverseDirection() CMssqlCommandBuilder
rewriteLimitOffsetSql() 为MSSQL数据库重写SQL以应用$limit > 0和$offset > 0。 CMssqlCommandBuilder

方法详细

applyLimit() 方法
public string applyLimit(string $sql, integer $limit, integer $offset)
$sql string SQL查询字符串
$limit integer 最大行数,若为-1则忽略limit。
$offset integer 行偏移,若为-1则忽略offset。
{return} string 带有limit和offset的SQL。
public function applyLimit($sql$limit$offset)
{
    
$limit $limit!==null intval($limit) : -1;
    
$offset $offset!==null intval($offset) : -1;
    if (
$limit && $offset <= 0//just limit
        
$sql preg_replace('/^([\s(])*SELECT( DISTINCT)?(?!\s*TOP\s*\()/i',"\\1SELECT\\2 TOP $limit"$sql);
    else if(
$limit && $offset 0)
        
$sql $this->rewriteLimitOffsetSql($sql$limit,$offset);
    return 
$sql;
}

This is a port from Prado Framework.

重写父类的实现。改变SQL以应用$limit和$offset。 应用带有offset的limit是根据SQL语句结构的 许多假设通过动态修改SQL实现的。 根据下面地址的附注完成修改: http://troels.arvin.dk/db/rdbms/#select-limit-offset

SELECT * FROM ( SELECT TOP n * FROM ( SELECT TOP z columns -- (z=n+skip) FROM tablename ORDER BY key ASC ) AS FOO ORDER BY key DESC -- ('FOO' may be anything) ) AS BAR ORDER BY key ASC -- ('BAR' may be anything)

Regular expressions are used to alter the SQL query. The resulting SQL query may be malformed for complex queries. The following restrictions apply

  • In particular, commas should NOT be used as part of the ordering expression or identifier. Commas must only be used for separating the ordering clauses.
  • In the ORDER BY clause, the column name should NOT be be qualified with a table name or view name. Alias the column names or use column index.
  • No clauses should follow the ORDER BY clause, e.g. no COMPUTE or FOR clauses.
  • checkCriteria() 方法
    protected CDbCrireria checkCriteria(CMssqlTableSchema $table, CDbCriteria $criteria)
    $table CMssqlTableSchema 表schema
    $criteria CDbCriteria 查询条件
    {return} CDbCrireria 修改后的查询条件
    protected function checkCriteria($table$criteria)
    {
        if (
    $criteria->offset && $criteria->order==='')
        {
            
    $criteria->order=is_array($table->primaryKey)?implode(',',$table->primaryKey):$table->primaryKey;
        }
        return 
    $criteria;
    }

    检查使用offset或limit的查询条件是否有order by子句。 重写父类的实现以检查带有offset的查询中order by子句是否已指定。 若未指定order by子句,则按主键排序。

    createCompositeInCondition() 方法
    protected string createCompositeInCondition(CDbTableSchema $table, array $values, string $prefix)
    $table CDbTableSchema 表schema
    $values array 要选择的主键值列表
    $prefix string 列前缀(以.结束)
    {return} string 选择的表达式。
    protected function createCompositeInCondition($table,$values,$prefix)
    {
        
    $vs=array();
        foreach(
    $values as $value)
        {
            
    $c=array();
            foreach(
    $value as $k=>$v)
                
    $c[]=$prefix.$table->columns[$k]->rawName.'='.$v;
            
    $vs[]='('.implode(' AND ',$c).')';
        }
        return 
    '('.implode(' OR ',$vs).')';
    }

    生成根据指定符合键值选择行的表达式。

    createCountCommand() 方法
    public CDbCommand createCountCommand(CDbTableSchema $table, CDbCriteria $criteria, string $alias='t')
    $table CDbTableSchema 表元数据。
    $criteria CDbCriteria 查询条件。
    $alias string 主表的别名。默认为‘t’。
    {return} CDbCommand 查询语句。
    public function createCountCommand($table,$criteria,$alias='t')
    {
        
    $criteria->order='';
        return 
    parent::createCountCommand($table$criteria,$alias);
    }

    为一个表创建COUNT(*)语句。 重写父类的实现以移除条件里的order子句(如果它存在)。

    createDeleteCommand() 方法
    public CDbCommand createDeleteCommand(CDbTableSchema $table, CDbCriteria $criteria)
    $table CDbTableSchema 表元数据
    $criteria CDbCriteria 查询条件
    {return} CDbCommand delete语句。
    public function createDeleteCommand($table,$criteria)
    {
        
    $criteria=$this->checkCriteria($table$criteria);
        return 
    parent::createDeleteCommand($table$criteria);
    }

    创建DELETE语句。 重写父类的实现以检查带有offset的查询中order by子句是否已指定。

    createFindCommand() 方法
    public CDbCommand createFindCommand(CDbTableSchema $table, CDbCriteria $criteria, string $alias='t')
    $table CDbTableSchema 表元数据。
    $criteria CDbCriteria 查询条件。
    $alias string 主表的别名。默认为‘t’。
    {return} CDbCommand 查询语句。
    public function createFindCommand($table,$criteria,$alias='t')
    {
        
    $criteria=$this->checkCriteria($table,$criteria);
        return 
    parent::createFindCommand($table,$criteria,$alias);

    }

    为一个表创建SELECT语句。 重写父类的实现以检查带有offset的查询中order by子句是否已指定。

    createUpdateCommand() 方法
    public CDbCommand createUpdateCommand(CDbTableSchema $table, array $data, CDbCriteria $criteria)
    $table CDbTableSchema 表元数据。
    $data array 要更新的列(名=>值)
    $criteria CDbCriteria 查询条件
    {return} CDbCommand update语句。
    public function createUpdateCommand($table,$data,$criteria)
    {
        
    $criteria=$this->checkCriteria($table,$criteria);
        
    $fields=array();
        
    $values=array();
        
    $bindByPosition=isset($criteria->params[0]);
        
    $i=0;
        foreach(
    $data as $name=>$value)
        {
            if((
    $column=$table->getColumn($name))!==null)
            {
                if (
    $table->sequenceName !== null && $column->isPrimaryKey === true) continue;
                if (
    $column->dbType === 'timestamp') continue;
                if(
    $value instanceof CDbExpression)
                {
                    
    $fields[]=$column->rawName.'='.$value->expression;
                    foreach(
    $value->params as $n=>$v)
                        
    $values[$n]=$v;
                }
                else if(
    $bindByPosition)
                {
                    
    $fields[]=$column->rawName.'=?';
                    
    $values[]=$column->typecast($value);
                }
                else
                {
                    
    $fields[]=$column->rawName.'='.self::PARAM_PREFIX.$i;
                    
    $values[self::PARAM_PREFIX.$i]=$column->typecast($value);
                    
    $i++;
                }
            }
        }
        if(
    $fields===array())
            throw new 
    CDbException(Yii::t('yii','No columns are being updated for table "{table}".',
                array(
    '{table}'=>$table->name)));
        
    $sql="UPDATE {$table->rawName} SET ".implode(', ',$fields);
        
    $sql=$this->applyJoin($sql,$criteria->join);
        
    $sql=$this->applyCondition($sql,$criteria->condition);
        
    $sql=$this->applyOrder($sql,$criteria->order);
        
    $sql=$this->applyLimit($sql,$criteria->limit,$criteria->offset);

        
    $command=$this->getDbConnection()->createCommand($sql);
        
    $this->bindValues($command,array_merge($values,$criteria->params));

        return 
    $command;
    }

    创建UPDATE语句。 重写父类的实现因为MSSQL不希望更新标识列。

    createUpdateCounterCommand() 方法
    public CDbCommand createUpdateCounterCommand(CDbTableSchema $table, CDbCriteria $counters, array $criteria)
    $table CDbTableSchema 表元数据
    $counters CDbCriteria 查询条件
    $criteria array 要更新的计数器(列名为索引的递增或递减计数器)。
    {return} CDbCommand update语句。
    public function createUpdateCounterCommand($table,$counters,$criteria)
    {
        
    $criteria=$this->checkCriteria($table$criteria);
        return 
    parent::createUpdateCounterCommand($table$counters$criteria);
    }

    创建递增或递减特定列的UPDATE语句。 重写父类的实现以检查带有offset的查询中order by子句是否已指定。

    findOrdering() 方法
    protected array findOrdering(string $sql)
    $sql string $sql
    {return} array 排序表达式作为键及排序方向作为值。
    protected function findOrdering($sql)
    {
        if(!
    preg_match('/ORDER BY/i'$sql))
            return array();
        
    $matches=array();
        
    $ordering=array();
        
    preg_match_all('/(ORDER BY)[\s"\[](.*)(ASC|DESC)?(?:[\s"\[]|$|COMPUTE|FOR)/i'$sql$matches);
        if(
    count($matches)>&& count($matches[2]) > 0)
        {
            
    $parts explode(','$matches[2][0]);
            foreach(
    $parts as $part)
            {
                
    $subs=array();
                if(
    preg_match_all('/(.*)[\s"\]](ASC|DESC)$/i'trim($part), $subs))
                {
                    if(
    count($subs) > && count($subs[2]) > 0)
                    {
                        
    $name='';
                        foreach(
    explode('.'$subs[1][0]) as $p)
                        {
                            if(
    $name!=='')
                                
    $name.='.';
                            
    $name.='[' trim($p'[]') . ']';
                        }
                        
    $ordering[$name] = $subs[2][0];
                    }
                    
    //else what?
                
    }
                else
                    
    $ordering[trim($part)] = 'ASC';
            }
        }

        
    // replacing column names with their alias names
        
    foreach($ordering as $name => $direction)
        {
            
    $matches = array();
            
    $pattern '/\s+'.str_replace(array('[',']'), array('\[','\]'), $name).'\s+AS\s+(\[[^\]]+\])/i';
            
    preg_match($pattern$sql$matches);
            if(isset(
    $matches[1]))
            {
                
    $ordering[$matches[1]] = $ordering[$name];
                unset(
    $ordering[$name]);
            }
        }

        return 
    $ordering;
    }

    基于简化语法:http://msdn2.microsoft.com/en-us/library/aa259187(SQL.80).aspx

    joinOrdering() 方法
    protected string joinOrdering(array $orders, string $newPrefix)
    $orders array 从findOrdering获得的order信息
    $newPrefix string 加在排序列的新表前缀。
    {return} string 连接后的order表达式。
    protected function joinOrdering($orders$newPrefix)
    {
        if(
    count($orders)>0)
        {
            
    $str=array();
            foreach(
    $orders as $column => $direction)
                
    $str[] = $column.' '.$direction;
            
    $orderBy 'ORDER BY '.implode(', '$str);
            return 
    preg_replace('/\s+\[[^\]]+\]\.(\[[^\]]+\])/i'' '.$newPrefix.'.\1'$orderBy);
        }
    }

    reverseDirection() 方法
    protected array reverseDirection(array $orders)
    $orders array 原始order信息
    {return} array 反转方向的order信息。
    protected function reverseDirection($orders)
    {
        foreach(
    $orders as $column => $direction)
            
    $orders[$column] = strtolower(trim($direction))==='desc' 'ASC' 'DESC';
        return 
    $orders;
    }

    rewriteLimitOffsetSql() 方法
    protected sql rewriteLimitOffsetSql(string $sql, integer $limit, integer $offset)
    $sql string SQL查询
    $limit integer $limit > 0
    $offset integer $offset > 0
    {return} sql 应用limit和offset的修改后SQL查询
    protected function rewriteLimitOffsetSql($sql$limit$offset)
    {
        
    $fetch $limit+$offset;
        
    $sql preg_replace('/^([\s(])*SELECT( DISTINCT)?(?!\s*TOP\s*\()/i',"\\1SELECT\\2 TOP $fetch"$sql);
        
    $ordering $this->findOrdering($sql);
        
    $orginalOrdering $this->joinOrdering($ordering'[__outer__]');
        
    $reverseordering $this->joinOrdering($this->reverseDirection($ordering), '[__inner__]');
        
    $sql "SELECT * FROM (SELECT TOP {$limit} * FROM ($sql) as [__inner__] {$reverseOrdering}) as [__outer__] {$orginalOrdering}";
        return 
    $sql;
    }

    为MSSQL数据库重写SQL以应用$limit > 0和$offset > 0。 参见http://troels.arvin.dk/db/rdbms/#select-limit-offset

上一篇:
下一篇: