Desenvolvido à partir do [Database Access Objects](db-dao.md), o query builder permite que você construa uma instrução SQL em um programático e independente de banco de dados. Comparado a escrever instruções SQL à mão, usar query builder lhe ajudará a escrever um código SQL relacional mais legível e gerar declarações SQL mais seguras.
> Observação: Geralmente, você trabalhará mais com o [[yii\db\Query]] do que com o [[yii\db\QueryBuilder]]. Este último é chamado pelo primeiro implicitamente quando você chama um dos métodos da query. O [[yii\db\QueryBuilder]] é a classe responsável por gerar instruções SGDBs dependentes (ex. colocar aspas em nomes de tabela/coluna) a partir de objetos de query independentemente do SGDB.
Para construir um objeto [[yii\db\Query]], você pode chamar diferentes métodos de construção de query para especificar diferentes partes de uma instrução SQL. Os nomes destes métodos assemelha-se as palavras-chave SQL utilizados nas partes correspondentes da instrução SQL. Por exemplo, para especificar a parte da instrução SQL `FROM`, você deve chamar o método `from()`. Todos os métodos de construção de query retornam o próprio objeto query, que permite você encadear várias chamadas em conjunto. A seguir, descreveremos o uso de cada método de construção de query.
O método [[yii\db\Query::select()|select()]] especifica o fragmento de uma instrução SQL `SELECT`. Você pode especificar colunas para ser selecionado em um array ou uma string, como mostrado abaixo. Os nomes das colunas que estão sendo selecionadas serão automaticamente envolvidas entre aspas quando a instrução SQL está sendo gerada a partir do objeto query.
Os nomes das colunas que estão sendo selecionadas podem incluir prefixos de tabela e/ou aliases de colunas, como você faz ao escrever instruções SQL manualmente.
Se você estiver usando um array para especificar as colunas, você também pode usar as chaves do array para especificar os aliases das colunas. Por exemplo, o código acima pode ser reescrito da seguinte forma,
Se você não chamar o método [[yii\db\Query::select()|select()]] na criação da query, o `*` será selecionado, o que significa selecionar *todas* as colunas.
Além dos nomes de colunas, você também pode selecionar expressões DB. Você deve usar o formato array quando utilizar uma expressão DB que contenha vírgula para evitar que sejam gerados nomes de colunas de forma equivocada. Por exemplo:
A partir da versão 2.0.1, você também pode selecionar sub-queries. Você deve especificar cada sub-query na forma de um objeto [[yii\db\Query]]. Por exemplo:
Você pode especificar todas tabelas a serem selecionadas a partir de uma string ou um array. O nome da tabela pode conter prefixos de esquema e/ou aliases de tabela, da mesma forma quando você escreve instruções SQL manualmente. Por exemplo:
O método [[yii\db\Query::where()|where()]] especifica o fragmento de uma instrução SQL `WHERE`. Você pode usar um dos três formatos para especificar uma condição `WHERE`:
Formato de string é mais usado para especificar condições `WHERE` muito simples. Esta forma é muito semelhante a condições `WHERE` escritas manualmente. Por exemplo:
NÃO incorporar variáveis diretamente na condição como exemplificado abaixo, especialmente se os valores das variáveis vêm de entradas de dados dos usuários finais, porque isso vai fazer a sua aplicação ficar sujeita a ataques de injeção de SQL.
```php
// Perigoso! NÃO faça isto a menos que você esteja muito certo que o $status deve ser um número inteiro.
$query->where("status=$status");
```
Ao usar parâmetro, você pode chamar [[yii\db\Query::params()|params()]] ou [[yii\db\Query::addParams()|addParams()]] para especificar os parâmetros separadamente.
// ...WHERE (`status` = 10) AND (`type` IS NULL) AND (`id` IN (4, 8, 15))
$query->where([
'status' => 10,
'type' => null,
'id' => [4, 8, 15],
]);
```
Como você pode ver, o query builder é inteligente o suficiente para lidar corretamente com valores que são nulos ou arrays. Você também pode usar sub-queries com o formato hash conforme mostrado abaixo:
```php
$userQuery = (new Query())->select('id')->from('user');
Formato operador lhe permite especificar arbitrariamente condições de uma forma programática. Ele tem o seguinte formato:
```php
[operator, operand1, operand2, ...]
```
onde cada um dos operandos pode ser especificado no formato string, formato hash ou formato operador recursivamente, enquanto o operador pode ser um dos seguintes procedimentos:
-`and`: os operandos devem ser concatenados juntos usando `AND`. Por exemplo,
`['and', 'id=1', 'id=2']` irá gerar `id=1 AND id=2`. Se um operando for um array,
ele será convertido para string usando as regras descritas aqui. Por exemplo,
`['and', 'type=1', ['or', 'id=1', 'id=2']]` irá gerar `type=1 AND (id=1 OR id=2)`.
O método NÃO vai fazer qualquer tratamento de escapar caracteres ou colocar aspas.
-`or`: similar ao operador `and` exceto pelo fato de que os operandos são concatenados usando `OR`.
-`between`: o operando 1 deve ser um nome de coluna, e os operandos 2 e 3 devem ser os valores de início e fim. Por exemplo, `['between', 'id', 1, 10]` irá gerar `id BETWEEN 1 AND 10`.
-`not between`: similar ao `between` exceto pelo fato de que `BETWEEN` é substituído por `NOT BETWEEN` na geração da condição.
-`in`: o operando 1 deve ser um nome de coluna ou uma expressão DB. O operando 2 pode ser tanto um array ou um objeto `Query`. Será gerado uma condição `IN`. Se o operando 2 for um array, representará o intervalo dos valores que a coluna ou expressão DB devem ser; se o operando 2 for um objeto `Query`, uma sub-query será gerada e usada como intervalo da coluna ou expressão DB. Por exemplo, `['in', 'id', [1, 2, 3]]` irá gerar `id IN (1, 2, 3)`. O método fará o tratamento apropriado de aspas e escape de valores para o intervalo. O operador `in` também suporta colunas compostas. Neste caso, o operando 1 deve ser um array de colunas, enquanto o operando 2 deve ser um array de arrays ou um objeto `Query` representando o intervalo das colunas.
-`not in`: similar ao operador `in` exceto pelo fato de que o `IN` é substituído por `NOT IN` na geração da condição.
-`like`: o operando 1 deve ser uma coluna ou uma expressão DB, e o operando 2 deve ser uma string ou um array representando o valor que a coluna ou expressão DB devem atender. Por exemplo, `['like', 'name', 'tester']` irá gerar `name LIKE '%tester%'`. Quando a faixa de valor é dado como um array, múltiplos predicados `LIKE` serão gerados e concatenadas utilizando `AND`. Por exemplo, `['like', 'name', ['test', 'sample']]` irá gerar `name LIKE '%test%' AND name LIKE '%sample%'`. Você também pode fornecer um terceiro operando opcional para especificar como escapar caracteres especiais nos valores. O operando deve ser um array de mapeamentos de caracteres especiais. Se este operando não for fornecido, um mapeamento de escape padrão será usado. Você pode usar `false` ou um array vazio para indicar que os valores já estão escapados e nenhum escape deve ser aplicado. Note-se que ao usar um mapeamento de escape (ou o terceiro operando não é fornecido), os valores serão automaticamente fechado dentro de um par de caracteres percentuais.
> Observação: Ao utilizar o SGDB PostgreSQL você também pode usar [`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE)
> em vez de `like` para diferenciar maiúsculas de minúsculas.
-`or like`: similar ao operador `like` exceto pelo fato de que `OR` é usado para concatenar os predicados `LIKE` quando o operando 2 é um array.
-`not like`: similar ao operador `like` exceto pelo fato de que `LIKE` é substituído por `NOT LIKE`.
-`or not like`: similar ao operador `not like` exceto pelo fato de que `OR` é usado para concatenar os predicados `NOT LIKE`.
-`exists`: requer um operador que deve ser uma instância de [[yii\db\Query]] representando a sub-query. Isto criará uma expressão `EXISTS (sub-query)`.
-`not exists`: similar ao operador `exists` e cria uma expressão `NOT EXISTS (sub-query)`.
-`>`, `<=`, ou qualquer outro operador válido que leva dois operandos: o primeiro operando deve ser um nome de coluna enquanto o segundo um valor. Ex., `['>', 'age', 10]` vai gerar `age>10`.
Você pode usar [[yii\db\Query::andWhere()|andWhere()]] ou [[yii\db\Query::orWhere()|orWhere()]] para acrescentar condições adicionais a uma condição já existente. Você pode chamá-los várias vezes para acrescentar várias condições separadamente. Por exemplo:
Ao construir condições `WHERE` a partir de entradas de usuários finais, você geralmente deseja ignorar os valores vazios. Por exemplo, em um formulário de busca que lhe permite pesquisar por nome ou e-mail, você poderia ignorar as condições nome/e-mail se não houver entradas destes valores. Para atingir este objetivo utilize o método [[yii\db\Query::filterWhere()|filterWhere()]]:
```php
// $username and $email são inputs dos usuário finais
$query->filterWhere([
'username' => $username,
'email' => $email,
]);
```
A única diferença entre [[yii\db\Query::filterWhere()|filterWhere()]] e [[yii\db\Query::where()|where()]] é que o primeiro irá ignorar valores vazios fornecidos na condição no [formato hash](#hash-format). Então se `$email` for vazio e `$username` não, o código acima resultará um SQL como: `...WHERE username=:username`.
> Observação: Um valor é considerado vazio se ele for null, um array vazio, uma string vazia ou uma string que consiste em apenas espaços em branco. Assim como [[yii\db\Query::andWhere()|andWhere()]] e [[yii\db\Query::orWhere()|orWhere()]], você pode usar [[yii\db\Query::andFilterWhere()|andFilterWhere()]] e [[yii\db\Query::orFilterWhere()|orFilterWhere()]] para inserir condições de filtro adicionais.
No código acima, as chaves do array são nomes de colunas e os valores são a direção da ordenação. A constante PHP `SORT_ASC` indica ordem crescente e `SORT_DESC` ordem decrescente. Se `ORDER BY` envolver apenas nomes simples de colunas, você pode especificá-lo usando string, da mesma forma como faria escrevendo SQL manualmente. Por exemplo:
Se o `GROUP BY` envolver apenas nomes de colunas simples, você pode especificá-lo usando uma string, da mesma forma como faria escrevendo SQL manualmente. Por exemplo:
O método [[yii\db\Query::having()|having()]] especifica o fragmento de uma instrução SQL `HAVING`. Este método recebe uma condição que pode ser especificada da mesma forma como é feito para o [where()](#where). Por exemplo:
Você pode chamar [[yii\db\Query::andHaving()|andHaving()]] ou [[yii\db\Query::orHaving()|orHaving()]] para incluir uma condição adicional para o fragmento `HAVING`. Por exemplo:
Os métodos [[yii\db\Query::limit()|limit()]] e [[yii\db\Query::offset()|offset()]] especificam os fragmentos de uma instrução SQL `LIMIT` e `OFFSET`. Por exemplo:
Se você especificar um limit ou offset inválido (Ex. um valor negativo), ele será ignorado.
> Observação: Para SGDBs que não suportam `LIMIT` e `OFFSET` (ex. MSSQL), query builder irá gerar uma instrução SQL que emula o comportamento `LIMIT`/`OFFSET`.
-`$on`: opcional, a condição do join, isto é, o fragmento `ON`. Por favor, consulte [where()](#where) para detalhes sobre como especificar uma condição.
Para unir múltiplas tabelas, chame os métodos join acima multiplas vezes, uma para cada tabela. Além de unir tabelas, você também pode unir sub-queries. Para fazê-lo, especifique a sub-queries a ser unida como um objeto [[yii\db\Query]]. Por exemplo:
- Outros métodos de agregação da query, incluindo [[yii\db\Query::sum()|sum($q)]], [[yii\db\Query::average()|average($q)]], [[yii\db\Query::max()|max($q)]], [[yii\db\Query::min()|min($q)]]. O parâmetro `$q` é obrigatório para estes métodos e pode ser um nome de uma coluna ou expressão DB. Por exemplo:
> Observação: O método [[yii\db\Query::one()|one()]] retorna apenas a primeira linha do resultado da query. Ele não adiciona `LIMIT 1` para a geração da sentença SQL. Isso é bom e preferível se você souber que a query retornará apenas uma ou algumas linhas de dados (Ex. se você estiver consultando com algumas chaves primárias). Entretanto, se a query pode retornar muitas linha de dados, você deve chamar `limit(1)` explicitamente para melhorar a performance. Ex., `(new \yii\db\Query())->from('user')->limit(1)->one()`.
Todos estes métodos query recebem um parâmetro opcional `$db` que representa a [[yii\db\Connection|conexão do DB]] que deve ser usada para realizar uma consulta no DB. Se você omitir este parâmetro, o [componente da aplicação](structure-application-components.md) `db` será usado como a conexão do DB. Abaixo está um outro exemplo do método `count()`:
* Cria um objeto [[yii\db\Command]] com a instrução SQL gerada;
* Chama um método query (ex. `queryAll()`) do [[yii\db\Command]] para executar a instrução SQL e retornar os dados.
Algumas vezes, você pode querer examinar ou usar a instrução SQL construído a partir de um objeto [[yii\db\Query]]. Você pode atingir este objetivo com o seguinte código:
Quando você chama [[yii\db\Query::all()|all()]], será retornado um array de linhas que são indexadas por inteiros consecutivos. Algumas vezes você pode querer indexa-los de forma diferente, tal como indexar por uma coluna ou valor de expressão em particular. Você pode atingir este objetivo chamando [[yii\db\Query::indexBy()|indexBy()]] antes de [[yii\db\Query::all()|all()]]. Por exemplo:
A função anônima recebe um parâmetro `$row` que contém os dados da linha atual e deve devolver um valor escalar que irá ser utilizada como índice para o valor da linha atual.
Ao trabalhar com grandes quantidades de dados, métodos tais como [[yii\db\Query::all()]] não são adequados porque eles exigem carregar todos os dados na memória. Para manter o requisito de memória baixa, Yii fornece o chamado suporte batch query. Um batch query faz uso do cursor de dados e obtém dados em lotes. Batch query pode ser usado como a seguir:
// $users é um array de 100 ou menos linha da tabela user
}
// ou se você quiser fazer uma iteração da linha uma por uma
foreach ($query->each() as $user) {
// $user representa uma linha de dados a partir da tabela user
}
```
O método [[yii\db\Query::batch()]] and [[yii\db\Query::each()]] retorna um objeto [[yii\db\BatchQueryResult]] que implementa a interface `Iterator` e, assim, pode ser utilizado na construção do `foreach`. Durante a primeira iteração, uma consulta SQL é feita à base de dados. Os dados são, então, baixados em lotes nas iterações restantes. Por padrão, o tamanho do batch é 100, significando 100 linhas de dados que serão baixados a cada batch. Você pode mudar o tamanho do batch passando o primeiro parâmetro para os métodos `batch()` ou `each()`.
Em comparação com o [[yii\db\Query::all()]], o batch query somente carrega 100 linhas de dados na memória a cada vez. Se você processar os dados e, em seguida, descartá-lo imediatamente, o batch query pode ajudar a reduzir o uso de memória. Se você especificar o resultado da query a ser indexado por alguma coluna via [[yii\db\Query::indexBy()]], o batch query ainda vai manter o índice adequado. Por exemplo: