Build the HAVING clause(s).

@return string
514317
protected function buildHavingConditions()
    {
        $join = ($this->havingType == 'AND') ? 'AND' : 'OR';
        $this->havingType = null;

        return $this->makeConditions('having', $join);
    }
311281
public function having($column, $operator = '=', $value, $logic = 'AND')
    {
        $having = $this->sql['having'] == '' ? 'HAVING' : " {$logic} ";
        $this->sql['having'] .= "{$having} {$column} {$operator} ";
        if ($value) {
            if (is_array($value)) {//手动传%s
                $this->bindParams = array_merge($this->bindParams, $value);
            } else {
                $this->sql['having'] .= ' %s ';
                $this->bindParams[] = $value;
            }
        }
        return $this;
    }
667280
public function getSelectQuery()
    {
        $sql = 'SELECT ' . $this->getSelect();
        $sql .= "\nFROM " . $this->getFrom();
        if ($this->where) {
            $sql .= "\nWHERE " . $this->getWhere();
        }
        if ($this->groupBy) {
            $sql .= "\nGROUP BY " . $this->getGroupBy();
        }
        if ($this->having) {
            $sql .= "\nHAVING " . $this->getHaving();
        }
        if ($this->orderBy) {
            $sql .= "\nORDER BY " . $this->getOrderBy();
        }
        if ($this->limit) {
            $sql .= "\nLIMIT " . $this->getLimit();
        }

        return $sql;
    }
263925
public function setHaving($having)
    {
        if (!empty($having)) {
            $this->query['having'] = $having;
        } else {
            unset($this->query['having']);
        }
        return $this;
    }
280742
private function buildQuery()
    {
        $this->validateQuery();

        $statement = "";
        if ($this->select !== null) {
            $statement .= sprintf("%s %s ", self::SELECT, $this->select);
        }
        if ($this->from !== null) {
            $statement .= sprintf("%s %s ", self::FROM, $this->from);
        }
        if ($this->where !== null) {
            $statement .= sprintf("%s %s ", self::WHERE, $this->where);
        }
        if ($this->orderBy !== null) {
            $statement .= sprintf("%s %s ", self::ORDER_BY, $this->orderBy);
        }
        if ($this->limit !== null) {
            $statement .= sprintf("%s %s ", self::LIMIT, $this->limit);
        }
        if ($this->offset !== null) {
            $statement .= sprintf("%s %s ", self::OFFSET, $this->offset);
        }

        return trim($statement);
    }
1159604
protected function build()
    {
        $sql = "SELECT\n\t"
            . $this->columns . "\n"
            . $this->from . "\n"
            . ($this->join    ? $this->join           : null)
            . ($this->where   ? $this->where . "\n"   : null)
            . ($this->groupby ? $this->groupby . "\n" : null)
            . ($this->orderby ? $this->orderby . "\n" : null)
            . ($this->limit   ? $this->limit . "\n"   : null)
            . ($this->offset  ? $this->offset . "\n"  : null)
            . ";";

        return $sql;
    }
91364
protected function buildValuesClause() {
		if (!empty($this->expression))
			return $this->expression;
		
		if (empty($this->value)) {
			$values = [];
			
			for ($i = 0, $n = count($this->valueList); $i < $n; $i++)
				$values[] = '%{' . $i . '}';
			
			return implode(',', $values);
		}
		

		$values = [];
		
		foreach ($this->columnList as $column) {
			$name = $this->parseColumn($column);
			$values[] = '#{' . $name . '}';
		}

		return implode(',', $values);
	}
1208833
public function having($conditions): self
    {
        if ($conditions[0] instanceof Closure) {
            $this->addClauseCondClosure('having', 'AND', $conditions[0]);

            return $this;
        }
        $this->having[] = ['and', $conditions];

        return $this;
    }
924624
public function having($conditions, $glue='AND')
  {
    if ( is_null($this->having) ){
      $glue = strtoupper($glue);
      $this->having = new Element('HAVING', $conditions, " $glue ");
    }
    else {
      $this->having->append($conditions);
    }

    return $this;
  }
1123903
public function build(): string
    {
        $join = '';
        $filter = '';
        $order = '';
        $limit = '';
        
        // Biuld joins
        if ($this->join) {
            $tmp = [];
            
            foreach ($this->join as $def) {
                $tmp[] = ' ' . $def['by'] . ' JOIN ' . '{db_prefix}' . (isset($def['as']) ? $def['table'] . ' AS ' . $def['as'] : $def['join']) . ' ON (' . $def['cond'] . ')';
            }
        }
        
        $join = isset($tmp) ? implode(' ', $tmp) : '';
        
        // Add counter
        if ($this->counter) {
            
            $tmp = '(@' . $this->counter['name'] . ':=' . '@' . $this->counter['name'] . '+' . $this->counter['step'] . ') AS ' . $this->counter['as'];
            
            array_unshift($this->fields, $tmp);
        }
        
        $fieldlist = $this->buildFieldlist();
        
        // Create filterstatement
        $filter = $this->filter ? 'WHERE ' . $this->filter : '';
        
        // Create group by statement
        $group_by = '';
        
        if ($this->group_by) {
            
            if (is_array($this->group_by)) {
                $this->group_by = implode(', ', $this->group_by);
            }
            
            $group_by = 'GROUP BY ' . $this->group_by;
        }
        
        // Create having statement
        $having = $this->having ? 'HAVING ' . $this->having : '';
        
        // Create order statement
        $order = $this->order ? 'ORDER BY ' . $this->order : '';
        
        // Create limit statement
        if ($this->limit) {
            
            $limit = ' LIMIT ';
            
            if (isset($this->limit['lower'])) {
                $limit .= $this->limit['lower'];
            }
            
            if (isset($this->limit['lower']) && isset($this->limit['upper'])) {
                $limit .= ',' . $this->limit['upper'];
            }
        }
        
        // Get complete tablename with alias while respecting called mathod
        $table = $this->buildTableName();
        
        switch ($this->method) {
            
            case 'UPDATE':
                
                // we have to build our own fieldlist
                $fields = [];
                
                foreach ($this->fields as $field) {
                    $fields[] = $field . '=:' . $field;
                }
                
                $pieces = [
                    $this->method,
                    $table,
                    'SET',
                    implode(',', $fields),
                    $filter
                ];
                
                break;
            
            case 'INSERT':
            case 'REPLACE':
                
                // Build values
                $values = [];
                
                foreach ($this->fields as $field) {
                    $values[] = ':' . $field;
                }
                
                if (empty($values)) {
                    Throw new QueryBuilderException('No values for INSERT or REPLACE found.');
                }
                
                $pieces = [
                    $this->method . ' INTO',
                    $table,
                    empty($fieldlist) || $fieldlist == '*' ? '' : '(' . $fieldlist . ')',
                    'VALUES (' . implode(', ', $values) . ')'
                ];
                
                break;
            
            case 'DELETE':
                
                $pieces = [
                    $this->method,
                    'FROM ' . $table,
                    $filter,
                    $order,
                    $limit
                ];
                
                break;
            
            default:
                
                $pieces = [
                    $this->method,
                    $fieldlist,
                    'FROM ' . $table,
                    $join,
                    $filter,
                    $group_by,
                    $having,
                    $order,
                    $limit
                ];
                
                break;
        }
        
        array_walk_recursive($pieces, function (&$data, $index) {
            $data = trim($data);
        });
        
        // Build sql string from pieces
        $this->sql = trim(implode(' ', $pieces));
        
        // Finally cleanup parameters by removing parameter not needed in query and parse array parameter into sql
        // string.
        foreach ($this->params as $key => $val) {
            
            // Do cleanup
            if (strpos($this->sql, $key) === false) {
                unset($this->params[$key]);
                continue;
            }
            
            // Replace array parameter against sql valid part
            if (is_array($val)) {
                $prepared = $this->prepareArrayQuery($key, $val);
                
                array_push($this->params, $prepared['params']);
                
                $this->sql = str_replace('prep:' . $key, $prepared['sql'], $this->sql);
            }
        }
        
        return $this->sql;
    }
211781
public function setHaving($having)
    {
        $having = func_num_args() > 1 ? func_get_args() : $having;
        $this->having = array();
        return $this->addHaving($having);
    }
1233318
public function having($conditions, $params = array())
    {
        $this->mergeParams($params);
        $this->query['having'] = $this->buildConditions($conditions);

        return $this;
    }
793436
public function build()
    {
        $sql = [
            $this->select->build(),
            $this->from->build(),
            $this->where->build(),
            $this->groupBy->build(),
            $this->having->build(),
            $this->orderBy->build(),
            $this->limit->build(),
            $this->union->build(),
        ];

        $this->values = array_merge(
            $this->where->getValues(),
            $this->having->getValues(),
            $this->union->getValues());

        $sql = implode(' ', array_filter($sql));

        // when there is no select statement then the query
        // is probably just a where subquery, thus does
        // not need to be prefixed with WHERE
        if ('WHERE ' === substr($sql, 0, 6)) {
            return substr($sql, 6);
        }

        return $sql;
    }
410089
public function getClauses()
    {
        // This is a cheap fix for `SELECT` statements that contain `UNION`.
        // The `ORDER BY` and `LIMIT` clauses should be at the end of the
        // statement.
        if (! empty($this->union)) {
            $clauses = static::$CLAUSES;
            unset($clauses['ORDER BY'], $clauses['LIMIT']);
            $clauses['ORDER BY'] = [
                'ORDER BY',
                3,
            ];
            $clauses['LIMIT'] = [
                'LIMIT',
                3,
            ];

            return $clauses;
        }

        return static::$CLAUSES;
    }
1156335
private function buildWheres()
    {
        $statement = '';

        foreach ($this->wheres as $where) {
            $statement = $where->build();
        }

        foreach ($this->andWheres as $andWhere) {
            $statement .= $andWhere->build();
        }

        foreach ($this->orWheres as $orWhere) {
            $statement .= $orWhere->build();
        }

        return $statement;
    }
144180
protected function havingBetween(array $having)
    {
        return $this->wrap($having['aggregate']) . ($having['not'] ? ' NOT BETWEEN ' : ' BETWEEN ') . $this->param($having['value1']) . ' AND ' . $this->param($having['value2']);
    }
48590
public function formatHaving(Predicate $having) {
        if ($having->getParams()) {
            return sprintf($this->getClause(self::HAVING), $this->formatPredicate($having));
        }

        return '';
    }