TigerZF
🌐Español

27.4. Zend_Db_Select

27.4.1. Introducción

El objeto Zend_Db_Select representa una sentencia de consulta SQL SELECT. La clase tiene métodos para añadir partes individuales a la consulta. Puede especificar algunas partes de la consulta usando métodos y estructuras de datos de PHP, y la clase forma la sintaxis SQL correcta por usted. Después de construir una consulta, puede ejecutarla como si la hubiera escrito como una cadena de texto.

El valor que ofrece Zend_Db_Select incluye:

  • Métodos orientados a objetos para especificar consultas SQL de forma incremental;

  • Abstracción independiente de la base de datos de algunas partes de la consulta SQL;

  • Entrecomillado automático de identificadores de metadatos en la mayoría de los casos, para permitir identificadores que contienen palabras reservadas de SQL y caracteres especiales;

  • Entrecomillado de identificadores y valores, para ayudar a reducir el riesgo de ataques de inyección SQL.

Usar Zend_Db_Select no es obligatorio. Para consultas SELECT muy sencillas, normalmente es más simple especificar toda la consulta SQL como una cadena y ejecutarla usando métodos del Adaptador como query() o fetchAll(). Usar Zend_Db_Select es útil si necesita ensamblar una consulta SELECT de forma procedimental, o basada en lógica condicional en su aplicación.

27.4.2. Creación de un objeto Select

Puede crear una instancia de un objeto Zend_Db_Select usando el método select() de un objeto Zend_Db_Adapter_Abstract.

Ejemplo 27.47. Ejemplo del método select() del adaptador de la base de datos

$db = Zend_Db::factory( ...options... );
$select = $db->select();

Otra forma de crear un objeto Zend_Db_Select es con su constructor, especificando el adaptador de la base de datos como argumento.

Ejemplo 27.48. Ejemplo de creación de un nuevo objeto Select

$db = Zend_Db::factory( ...options... );
$select = new Zend_Db_Select($db);

27.4.3. Construcción de consultas Select

Al construir la consulta, puede añadir las cláusulas de la consulta una por una. Hay un método independiente para añadir cada cláusula al objeto Zend_Db_Select.

Ejemplo 27.49. Ejemplo del uso de métodos para añadir cláusulas

// Create the Zend_Db_Select object
$select = $db->select();

// Add a FROM clause
$select->from( ...specify table and columns... )

// Add a WHERE clause
$select->where( ...specify search criteria... )

// Add an ORDER BY clause
$select->order( ...specify sorting criteria... );

También puede usar la mayoría de los métodos del objeto Zend_Db_Select con una cómoda interfaz fluida. Una interfaz fluida significa que cada método devuelve una referencia al objeto sobre el que se llamó, de modo que puede llamar inmediatamente a otro método.

Ejemplo 27.50. Ejemplo del uso de la interfaz fluida

$select = $db->select()
    ->from( ...specify table and columns... )
    ->where( ...specify search criteria... )
    ->order( ...specify sorting criteria... );

Los ejemplos de esta sección muestran el uso de la interfaz fluida, pero puede usar la interfaz no fluida en todos los casos. A menudo es necesario usar la interfaz no fluida, por ejemplo, si su aplicación necesita realizar alguna lógica antes de añadir una cláusula a una consulta.

27.4.3.1. Añadir una cláusula FROM

Especifique la tabla de esta consulta usando el método from(). Puede especificar el nombre de la tabla como una cadena simple. Zend_Db_Select aplica entrecomillado de identificador alrededor del nombre de la tabla, de modo que puede usar caracteres especiales.

Ejemplo 27.51. Ejemplo del método from()

// Build this query:
//   SELECT *
//   FROM "products"

$select = $db->select()
             ->from( 'products' );

También puede especificar el nombre de correlación (a veces llamado el "alias de tabla") de una tabla. En lugar de una cadena simple, use un array asociativo que asigne el nombre de correlación al nombre de la tabla. En otras cláusulas de la consulta SQL, use este nombre de correlación. Si su consulta une más de una tabla, Zend_Db_Select genera nombres de correlación únicos basados en los nombres de las tablas, para cualquier tabla para la que no especifique el nombre de correlación.

Ejemplo 27.52. Ejemplo de especificación de un nombre de correlación de tabla

// Build this query:
//   SELECT p.*
//   FROM "products" AS p

$select = $db->select()
             ->from( array('p' => 'products') );

Algunas marcas de RDBMS admiten un especificador de esquema delante de una tabla. Puede especificar el nombre de la tabla como "schemaName.tableName", donde Zend_Db_Select entrecomilla cada parte por separado, o puede especificar el nombre del esquema por separado. Un nombre de esquema especificado en el nombre de la tabla tiene precedencia sobre un esquema proporcionado por separado en caso de que se proporcionen ambos.

Ejemplo 27.53. Ejemplo de especificación de un nombre de esquema

// Build this query:
//   SELECT *
//   FROM "myschema"."products"

$select = $db->select()
             ->from( 'myschema.products' );

// or

$select = $db->select()
             ->from('products', '*', 'myschema');

27.4.3.2. Añadir columnas

En el segundo argumento del método from(), puede especificar las columnas que se seleccionarán de la tabla respectiva. Si no especifica ninguna columna, el valor predeterminado es "*", el comodín SQL para "todas las columnas".

Puede listar las columnas en un array simple de cadenas, o como una asignación asociativa de alias de columna a nombre de columna. Si solo tiene una columna que consultar, y no necesita especificar un alias de columna, puede listarla como una cadena simple en lugar de un array.

Si proporciona un array vacío como argumento de columnas, no se incluye ninguna columna de la tabla respectiva en el conjunto de resultados. Vea un ejemplo de código en la sección sobre el método join().

Puede especificar el nombre de columna como "correlationName.columnName". Zend_Db_Select entrecomilla cada parte por separado. Si no especifica un nombre de correlación para una columna, se usa el nombre de correlación de la tabla nombrada en el método from() actual.

Ejemplo 27.54. Ejemplos de especificación de columnas

// Build this query:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id', 'product_name'));

// Build the same query, specifying correlation names:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('p.product_id', 'p.product_name'));

// Build this query with an alias for one column:
//   SELECT p."product_id" AS prodno, p."product_name"
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('prodno' => 'product_id', 'product_name'));

27.4.3.3. Añadir columnas de expresión

Las columnas en las consultas SQL a veces son expresiones, no simplemente nombres de columna de una tabla. A las expresiones no se les debe aplicar nombres de correlación ni entrecomillado. Si su cadena de columna contiene paréntesis, Zend_Db_Select la reconoce como una expresión.

También puede crear un objeto de tipo Zend_Db_Expr explícitamente, para evitar que una cadena sea tratada como un nombre de columna. Zend_Db_Expr es una clase mínima que contiene una única cadena. Zend_Db_Select reconoce objetos de tipo Zend_Db_Expr y los convierte de nuevo a cadena, pero no aplica ninguna alteración, como entrecomillado o nombres de correlación.

[Note] Nota

Usar Zend_Db_Expr para nombres de columna no es necesario si su expresión de columna contiene paréntesis; Zend_Db_Select reconoce los paréntesis y trata la cadena como una expresión, omitiendo el entrecomillado y los nombres de correlación.

Ejemplo 27.55. Ejemplos de especificación de columnas que contienen expresiones

// Build this query:
//   SELECT p."product_id", LOWER(product_name)
//   FROM "products" AS p
// An expression with parentheses implicitly becomes
// a Zend_Db_Expr.

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id', 'LOWER(product_name)'));

// Build this query:
//   SELECT p."product_id", (p.cost * 1.08) AS cost_plus_tax
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id',
                          'cost_plus_tax' => '(p.cost * 1.08)')
                   );

// Build this query using Zend_Db_Expr explicitly:
//   SELECT p."product_id", p.cost * 1.08 AS cost_plus_tax
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id',
                          'cost_plus_tax' =>
                              new Zend_Db_Expr('p.cost * 1.08'))
                    );

En los casos anteriores, Zend_Db_Select no altera la cadena para aplicar nombres de correlación o entrecomillado de identificador. Si esos cambios son necesarios para resolver ambigüedad, debe hacer los cambios manualmente en la cadena.

Si sus nombres de columna son palabras clave SQL o contienen caracteres especiales, debería usar el método quoteIdentifier() del Adaptador e interpolar el resultado en la cadena. El método quoteIdentifier() usa el entrecomillado SQL para delimitar el identificador, lo que deja claro que es un identificador para una tabla o una columna, y no cualquier otra parte de la sintaxis SQL.

Su código es más independiente de la base de datos si usa el método quoteIdentifier() en lugar de escribir comillas literalmente en su cadena, porque algunas marcas de RDBMS usan símbolos no estándar para entrecomillar identificadores. El método quoteIdentifier() está diseñado para usar los símbolos de entrecomillado apropiados según el tipo de adaptador. El método quoteIdentifier() también escapa cualquier carácter de comilla que aparezca dentro del propio nombre del identificador.

Ejemplo 27.56. Ejemplos de entrecomillado de columnas en una expresión

// Build this query,
// quoting the special column name "from" in the expression:
//   SELECT p."from" + 10 AS origin
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('origin' =>
                              '(p.' . $db->quoteIdentifier('from') . ' + 10)')
                   );

27.4.3.4. Añadir columnas a una tabla FROM o JOIN existente

Puede haber casos en los que desee añadir columnas a una tabla FROM o JOIN existente después de que se hayan llamado esos métodos. El método columns() le permite añadir columnas específicas en cualquier momento antes de que se ejecute la consulta. Puede proporcionar las columnas como una cadena o Zend_Db_Expr, o como un array de estos elementos. El segundo argumento de este método puede omitirse, lo que implica que las columnas se añadirán a la tabla FROM; de lo contrario, debe usarse un nombre de correlación existente.

Ejemplo 27.57. Ejemplos de añadir columnas con el método columns()

// Build this query:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'), 'product_id')
             ->columns('product_name');

// Build the same query, specifying correlation names:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p

$select = $db->select()
             ->from(array('p' => 'products'), 'p.product_id')
             ->columns('product_name', 'p');
             // Alternatively use columns('p.product_name')

27.4.3.5. Añadir otra tabla a la consulta con JOIN

Muchas consultas útiles implican usar un JOIN para combinar filas de varias tablas. Puede añadir tablas a una consulta Zend_Db_Select usando el método join(). Usar este método es similar a usar el método from(), excepto que también puede especificar una condición de unión en la mayoría de los casos.

Ejemplo 27.58. Ejemplo del método join()

// Build this query:
//   SELECT p."product_id", p."product_name", l.*
//   FROM "products" AS p JOIN "line_items" AS l
//     ON p.product_id = l.product_id

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id', 'product_name'))
             ->join(array('l' => 'line_items'),
                    'p.product_id = l.product_id');

El segundo argumento de join() es una cadena que es la condición de unión. Esta es una expresión que declara los criterios por los cuales las filas de una tabla coinciden con las filas de la otra tabla. Puede usar nombres de correlación en esta expresión.

[Note] Nota

No se aplica ningún entrecomillado a la expresión que especifica para la condición de unión; si tiene nombres de columna que necesitan ser entrecomillados, debe usar quoteIdentifier() al formar la cadena para la condición de unión.

El tercer argumento de join() es un array de nombres de columna, como el usado en el método from(). El valor predeterminado es "*", y admite nombres de correlación, expresiones y Zend_Db_Expr de la misma manera que el array de nombres de columna en el método from().

Para no seleccionar ninguna columna de una tabla, use un array vacío como lista de columnas. Este uso también funciona en el método from(), pero normalmente desea algunas columnas de la tabla principal en sus consultas, mientras que podría no querer ninguna columna de una tabla unida.

Ejemplo 27.59. Ejemplo de especificación de ninguna columna

// Build this query:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p JOIN "line_items" AS l
//     ON p.product_id = l.product_id

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id', 'product_name'))
             ->join(array('l' => 'line_items'),
                    'p.product_id = l.product_id',
                    array() ); // empty list of columns

Observe el array() vacío en el ejemplo anterior en lugar de una lista de columnas de la tabla unida.


SQL tiene varios tipos de uniones. Vea la lista siguiente para los métodos que admiten distintos tipos de unión en Zend_Db_Select.

  • INNER JOIN con los métodos join(table, join, [columns]) o joinInner(table, join, [columns]).

    Este puede ser el tipo de unión más común. Las filas de cada tabla se comparan usando la condición de unión que especifique. El conjunto de resultados incluye solo las filas que satisfacen la condición de unión. El conjunto de resultados puede estar vacío si ninguna fila satisface esta condición.

    Todas las marcas de RDBMS admiten este tipo de unión.

  • LEFT JOIN con el método joinLeft(table, condition, [columns]).

    Se incluyen todas las filas de la tabla del operando izquierdo, se incluyen las filas coincidentes de la tabla del operando derecho, y las columnas de la tabla del operando derecho se rellenan con NULL si no existe ninguna fila que coincida con la tabla izquierda.

    Todas las marcas de RDBMS admiten este tipo de unión.

  • RIGHT JOIN con el método joinRight(table, condition, [columns]).

    La unión externa derecha es el complemento de la unión externa izquierda. Se incluyen todas las filas de la tabla del operando derecho, se incluyen las filas coincidentes de la tabla del operando izquierdo, y las columnas de la tabla del operando izquierdo se rellenan con NULL si no existe ninguna fila que coincida con la tabla derecha.

    Algunas marcas de RDBMS no admiten este tipo de unión, pero en general cualquier unión derecha se puede representar como una unión izquierda invirtiendo el orden de las tablas.

  • FULL JOIN con el método joinFull(table, condition, [columns]).

    Una unión externa completa es como combinar una unión externa izquierda y una unión externa derecha. Se incluyen todas las filas de ambas tablas, emparejadas entre sí en la misma fila del conjunto de resultados si satisfacen la condición de unión, y de lo contrario emparejadas con NULL en lugar de columnas de la otra tabla.

    Algunas marcas de RDBMS no admiten este tipo de unión.

  • CROSS JOIN con el método joinCross(table, [columns]).

    Una unión cruzada es un producto cartesiano. Cada fila de la primera tabla se empareja con cada fila de la segunda tabla. Por lo tanto, el número de filas en el conjunto de resultados es igual al producto del número de filas de cada tabla. Puede filtrar el conjunto de resultados usando condiciones en una cláusula WHERE; de esta manera una unión cruzada es similar a la antigua sintaxis de unión SQL-89.

    El método joinCross() no tiene parámetro para especificar la condición de unión. Algunas marcas de RDBMS no admiten este tipo de unión.

  • NATURAL JOIN con el método joinNatural(table, [columns]).

    Una unión natural compara cualquier columna que aparezca con el mismo nombre en ambas tablas. La comparación es de igualdad de todas las columnas; comparar las columnas usando desigualdad no es una unión natural. Solo se admiten uniones naturales internas en esta API, aunque SQL permite también uniones naturales externas.

    El método joinNatural() no tiene parámetro para especificar la condición de unión.

Además de estos métodos de unión, puede simplificar sus consultas usando los métodos JoinUsing. En lugar de proporcionar una condición completa a su unión, simplemente pasa el nombre de la columna por la que unir y el objeto Zend_Db_Select completa la condición por usted.

Ejemplo 27.60. Ejemplo del método joinUsing()

// Build this query:
//   SELECT *
//   FROM "table1"
//   JOIN "table2"
//   ON "table1".column1 = "table2".column1
//   WHERE column2 = 'foo'

$select = $db->select()
             ->from('table1')
             ->joinUsing('table2', 'column1')
             ->where('column2 = ?', 'foo');

Cada uno de los métodos de unión aplicables en el componente Zend_Db_Select tiene un método 'using' correspondiente.

  • joinUsing(table, join, [columns]) y joinInnerUsing(table, join, [columns])

  • joinLeftUsing(table, join, [columns])

  • joinRightUsing(table, join, [columns])

  • joinFullUsing(table, join, [columns])

27.4.3.6. Añadir una cláusula WHERE

Puede especificar criterios para restringir las filas del conjunto de resultados usando el método where(). El primer argumento de este método es una expresión SQL, y esta expresión se usa en una cláusula SQL WHERE de la consulta.

Ejemplo 27.61. Ejemplo del método where()

// Build this query:
//   SELECT product_id, product_name, price
//   FROM "products"
//   WHERE price > 100.00

$select = $db->select()
             ->from('products',
                    array('product_id', 'product_name', 'price'))
             ->where('price > 100.00');

[Note] Nota

No se aplica ningún entrecomillado a las expresiones proporcionadas a los métodos where() u orWhere(). Si tiene nombres de columna que necesitan ser entrecomillados, debe usar quoteIdentifier() al formar la cadena para la condición.

El segundo argumento del método where() es opcional. Es un valor que se sustituye en la expresión. Zend_Db_Select entrecomilla el valor y lo sustituye por un símbolo de interrogación ("?") en la expresión.

Ejemplo 27.62. Ejemplo de un parámetro en el método where()

// Build this query:
//   SELECT product_id, product_name, price
//   FROM "products"
//   WHERE (price > 100.00)

$minimumPrice = 100;

$select = $db->select()
             ->from('products',
                    array('product_id', 'product_name', 'price'))
             ->where('price > ?', $minimumPrice);

Puede pasar un array como segundo parámetro al método where() cuando use el operador SQL IN.

Ejemplo 27.63. Ejemplo de un parámetro array en el método where()

// Build this query:
//   SELECT product_id, product_name, price
//   FROM "products"
//   WHERE (product_id IN (1, 2, 3))

$productIds = array(1, 2, 3);

$select = $db->select()
             ->from('products',
                    array('product_id', 'product_name', 'price'))
             ->where('product_id IN (?)', $productIds);

Puede invocar el método where() varias veces en el mismo objeto Zend_Db_Select. La consulta resultante combina los múltiples términos usando AND entre ellos.

Ejemplo 27.64. Ejemplo de varios métodos where()

// Build this query:
//   SELECT product_id, product_name, price
//   FROM "products"
//   WHERE (price > 100.00)
//     AND (price < 500.00)

$minimumPrice = 100;
$maximumPrice = 500;

$select = $db->select()
             ->from('products',
                    array('product_id', 'product_name', 'price'))
             ->where('price > ?', $minimumPrice)
             ->where('price < ?', $maximumPrice);

Si necesita combinar términos usando OR, use el método orWhere(). Este método se usa de la misma manera que el método where(), excepto que el término especificado va precedido de OR, en lugar de AND.

Ejemplo 27.65. Ejemplo del método orWhere()

// Build this query:
//   SELECT product_id, product_name, price
//   FROM "products"
//   WHERE (price < 100.00)
//     OR (price > 500.00)

$minimumPrice = 100;
$maximumPrice = 500;

$select = $db->select()
             ->from('products',
                    array('product_id', 'product_name', 'price'))
             ->where('price < ?', $minimumPrice)
             ->orWhere('price > ?', $maximumPrice);

Zend_Db_Select pone automáticamente paréntesis alrededor de cada expresión que especifique usando los métodos where() u orWhere(). Esto ayuda a garantizar que la precedencia de operadores booleanos no cause resultados inesperados.

Ejemplo 27.66. Ejemplo de puesta entre paréntesis de expresiones booleanas

// Build this query:
//   SELECT product_id, product_name, price
//   FROM "products"
//   WHERE (price < 100.00 OR price > 500.00)
//     AND (product_name = 'Apple')

$minimumPrice = 100;
$maximumPrice = 500;
$prod = 'Apple';

$select = $db->select()
             ->from('products',
                    array('product_id', 'product_name', 'price'))
             ->where("price < $minimumPrice OR price > $maximumPrice")
             ->where('product_name = ?', $prod);

En el ejemplo anterior, los resultados serían bastante diferentes sin los paréntesis, porque AND tiene mayor precedencia que OR. Zend_Db_Select aplica los paréntesis de modo que el efecto es que cada expresión en llamadas sucesivas a where() se une más estrechamente que el AND que combina las expresiones.

27.4.3.7. Añadir una cláusula GROUP BY

En SQL, la cláusula GROUP BY le permite reducir las filas de un conjunto de resultados de consulta a una fila por cada valor único encontrado en las columnas nombradas en la cláusula GROUP BY.

En Zend_Db_Select, puede especificar las columnas a usar para calcular los grupos de filas usando el método group(). El argumento de este método es una columna o un array de columnas a usar en la cláusula GROUP BY.

Ejemplo 27.67. Ejemplo del método group()

// Build this query:
//   SELECT p."product_id", COUNT(*) AS line_items_per_product
//   FROM "products" AS p JOIN "line_items" AS l
//     ON p.product_id = l.product_id
//   GROUP BY p.product_id

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id'))
             ->join(array('l' => 'line_items'),
                    'p.product_id = l.product_id',
                    array('line_items_per_product' => 'COUNT(*)'))
             ->group('p.product_id');

Al igual que en el array de columnas del método from(), puede usar nombres de correlación en las cadenas de nombre de columna, y la columna se entrecomilla como identificador a menos que la cadena contenga paréntesis o sea un objeto de tipo Zend_Db_Expr.

27.4.3.8. Añadir una cláusula HAVING

En SQL, la cláusula HAVING aplica una condición de restricción sobre grupos de filas. Esto es similar a cómo una cláusula WHERE aplica una condición de restricción sobre filas. Pero las dos cláusulas son diferentes porque las condiciones WHERE se aplican antes de que se definan los grupos, mientras que las condiciones HAVING se aplican después de que se definan los grupos.

En Zend_Db_Select, puede especificar condiciones para restringir grupos usando el método having(). Su uso es similar al del método where(). El primer argumento es una cadena que contiene una expresión SQL. El segundo argumento opcional es un valor que se usa para reemplazar un marcador de posición de parámetro posicional en la expresión SQL. Las expresiones proporcionadas en varias invocaciones del método having() se combinan usando el operador booleano AND, o el operador OR si usa el método orHaving().

Ejemplo 27.68. Ejemplo del método having()

// Build this query:
//   SELECT p."product_id", COUNT(*) AS line_items_per_product
//   FROM "products" AS p JOIN "line_items" AS l
//     ON p.product_id = l.product_id
//   GROUP BY p.product_id
//   HAVING line_items_per_product > 10

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id'))
             ->join(array('l' => 'line_items'),
                    'p.product_id = l.product_id',
                    array('line_items_per_product' => 'COUNT(*)'))
             ->group('p.product_id')
             ->having('line_items_per_product > 10');

[Note] Nota

No se aplica ningún entrecomillado a las expresiones proporcionadas a los métodos having() u orHaving(). Si tiene nombres de columna que necesitan ser entrecomillados, debe usar quoteIdentifier() al formar la cadena para la condición.

27.4.3.9. Añadir una cláusula ORDER BY

En SQL, la cláusula ORDER BY especifica una o más columnas o expresiones por las que se ordena el conjunto de resultados de una consulta. Si se listan varias columnas, las columnas secundarias se usan para resolver empates; el orden de clasificación se determina por las columnas secundarias si las columnas precedentes contienen valores idénticos. La ordenación predeterminada es de menor a mayor valor. También puede ordenar de mayor a menor valor para una columna dada en la lista especificando la palabra clave DESC después de esa columna.

En Zend_Db_Select, puede usar el método order() para especificar una columna o un array de columnas por las que ordenar. Cada elemento del array es una cadena que nombra una columna, opcionalmente seguida de la palabra clave ASC DESC, separada por un espacio.

Al igual que en los métodos from() y group(), los nombres de columna se entrecomillan como identificadores, a menos que contengan paréntesis o sean un objeto de tipo Zend_Db_Expr.

Ejemplo 27.69. Ejemplo del método order()

// Build this query:
//   SELECT p."product_id", COUNT(*) AS line_items_per_product
//   FROM "products" AS p JOIN "line_items" AS l
//     ON p.product_id = l.product_id
//   GROUP BY p.product_id
//   ORDER BY "line_items_per_product" DESC, "product_id"

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id'))
             ->join(array('l' => 'line_items'),
                    'p.product_id = l.product_id',
                    array('line_items_per_product' => 'COUNT(*)'))
             ->group('p.product_id')
             ->order(array('line_items_per_product DESC',
                           'product_id'));

27.4.3.10. Añadir una cláusula LIMIT

Algunas marcas de RDBMS extienden SQL con una cláusula de consulta conocida como la cláusula LIMIT. Esta cláusula reduce el número de filas en el conjunto de resultados a lo sumo a un número que usted especifique. También puede especificar que se omita un número de filas antes de empezar a mostrar el resultado. Esta característica facilita tomar un subconjunto de un conjunto de resultados, por ejemplo al mostrar resultados de consulta en páginas progresivas de salida.

En Zend_Db_Select, puede usar el método limit() para especificar el número de filas y el número de filas a omitir. El primer argumento de este método es el número de filas deseado. El segundo argumento es el número de filas a omitir.

Ejemplo 27.70. Ejemplo del método limit()

// Build this query:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p
//   LIMIT 10, 20
// Equivalent to:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p
//   LIMIT 20 OFFSET 10

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id', 'product_name'))
             ->limit(20, 10);

[Note] Nota

La sintaxis LIMIT no es admitida por todas las marcas de RDBMS. Algunos RDBMS requieren una sintaxis diferente para admitir una funcionalidad similar. Cada clase Zend_Db_Adapter_Abstract incluye un método para producir el SQL apropiado para ese RDBMS.

Use el método limitPage() como una forma alternativa de especificar el número de filas y el desplazamiento. Este método le permite limitar el conjunto de resultados a uno de una serie de subconjuntos de longitud fija de filas del conjunto de resultados total de la consulta. En otras palabras, especifica la longitud de una "página" de resultados, y el número ordinal de la única página de resultados que desea que la consulta devuelva. El número de página es el primer argumento del método limitPage(), y la longitud de página es el segundo argumento. Ambos argumentos son obligatorios; no tienen valores predeterminados.

Ejemplo 27.71. Ejemplo del método limitPage()

// Build this query:
//   SELECT p."product_id", p."product_name"
//   FROM "products" AS p
//   LIMIT 10, 20

$select = $db->select()
             ->from(array('p' => 'products'),
                    array('product_id', 'product_name'))
             ->limitPage(2, 10);

27.4.3.11. Añadir el modificador de consulta DISTINCT

El método distinct() le permite añadir la palabra clave DISTINCT a su consulta SQL.

Ejemplo 27.72. Ejemplo del método distinct()

// Build this query:
//   SELECT DISTINCT p."product_name"
//   FROM "products" AS p

$select = $db->select()
             ->distinct()
             ->from(array('p' => 'products'), 'product_name');

27.4.3.12. Añadir el modificador de consulta FOR UPDATE

El método forUpdate() le permite añadir el modificador FOR UPDATE a su consulta SQL.

Ejemplo 27.73. Ejemplo del método forUpdate()

// Build this query:
//   SELECT FOR UPDATE p.*
//   FROM "products" AS p

$select = $db->select()
             ->forUpdate()
             ->from(array('p' => 'products'));

27.4.3.13. Construcción de una consulta UNION

Puede construir consultas de unión con Zend_Db_Select pasando un array de objetos Zend_Db_Select o cadenas de consulta SQL al método union(). Como segundo parámetro puede pasar las constantes Zend_Db_Select::SQL_UNION o Zend_Db_Select::SQL_UNION_ALL para especificar qué tipo de unión desea realizar.

Ejemplo 27.74. Ejemplo del método union()

$sql1 = $db->select();
$sql2 = "SELECT ...";

$select = $db->select()
    ->union(array($sql1, $sql2))
    ->order("id");

27.4.4. Ejecución de consultas Select

Esta sección describe cómo ejecutar la consulta representada por un objeto Zend_Db_Select.

27.4.4.1. Ejecución de consultas Select desde el adaptador Db

Puede ejecutar la consulta representada por el objeto Zend_Db_Select pasándola como primer argumento al método query() de un objeto Zend_Db_Adapter_Abstract. Use objetos Zend_Db_Select en lugar de una consulta en forma de cadena.

El método query() devuelve un objeto de tipo Zend_Db_Statement o PDOStatement, según el tipo de adaptador.

Ejemplo 27.75. Ejemplo usando el método query() del adaptador Db

$select = $db->select()
             ->from('products');

$stmt = $db->query($select);
$result = $stmt->fetchAll();

27.4.4.2. Ejecución de consultas Select desde el objeto

Como alternativa a usar el método query() del objeto adaptador, puede usar el método query() del objeto Zend_Db_Select. Ambos métodos devuelven un objeto de tipo Zend_Db_Statement o PDOStatement, según el tipo de adaptador.

Ejemplo 27.76. Ejemplo usando el método query del objeto Select

$select = $db->select()
             ->from('products');

$stmt = $select->query();
$result = $stmt->fetchAll();

27.4.4.3. Conversión de un objeto Select a una cadena SQL

Si necesita acceso a una representación en cadena de la consulta SQL correspondiente al objeto Zend_Db_Select, use el método __toString().

Ejemplo 27.77. Ejemplo del método __toString()

$select = $db->select()
             ->from('products');

$sql = $select->__toString();
echo "$sql\n";

// The output is the string:
//   SELECT * FROM "products"

27.4.5. Otros métodos

Esta sección describe otros métodos de la clase Zend_Db_Select que no se han cubierto anteriormente: getPart() y reset().

27.4.5.1. Obtención de partes del objeto Select

El método getPart() devuelve una representación de una parte de su consulta SQL. Por ejemplo, puede usar este método para devolver el array de expresiones de la cláusula WHERE, o el array de columnas (o expresiones de columna) que están en la lista SELECT, o los valores del número de filas y el desplazamiento para la cláusula LIMIT.

El valor de retorno no es una cadena que contenga un fragmento de sintaxis SQL. El valor de retorno es una representación interna, que normalmente es una estructura de array que contiene valores y expresiones. Cada parte de la consulta tiene una estructura diferente.

El único argumento del método getPart() es una cadena que identifica qué parte de la consulta Select se debe devolver. Por ejemplo, la cadena 'from' identifica la parte del objeto Select que almacena información sobre las tablas en la cláusula FROM, incluidas las tablas unidas.

La clase Zend_Db_Select define constantes que puede usar para partes de la consulta SQL. Puede usar estas definiciones de constantes, o puede usar las cadenas literales.

Tabla 27.2. Constantes usadas por getPart() y reset()

Constante Valor de cadena
Zend_Db_Select::DISTINCT 'distinct'
Zend_Db_Select::FOR_UPDATE 'forupdate'
Zend_Db_Select::COLUMNS 'columns'
Zend_Db_Select::FROM 'from'
Zend_Db_Select::WHERE 'where'
Zend_Db_Select::GROUP 'group'
Zend_Db_Select::HAVING 'having'
Zend_Db_Select::ORDER 'order'
Zend_Db_Select::LIMIT_COUNT 'limitcount'
Zend_Db_Select::LIMIT_OFFSET 'limitoffset'

Ejemplo 27.78. Ejemplo del método getPart()

$select = $db->select()
             ->from('products')
             ->order('product_id');

// You can use a string literal to specify the part
$orderData = $select->getPart( 'order' );

// You can use a constant to specify the same part
$orderData = $select->getPart( Zend_Db_Select::ORDER );

// The return value may be an array structure, not a string.
// Each part has a different structure.
print_r( $orderData );

27.4.5.2. Restablecimiento de partes del objeto Select

El método reset() le permite borrar una parte especificada de la consulta SQL, o bien borrar todas las partes de la consulta SQL si omite el argumento.

El único argumento es opcional. Puede especificar la parte de la consulta que se debe borrar, usando las mismas cadenas que usó en el argumento del método getPart(). La parte de la consulta que especifique se restablece a un estado predeterminado.

Si omite el parámetro, reset() cambia todas las partes de la consulta a su estado predeterminado. Esto hace que el objeto Zend_Db_Select sea equivalente a un objeto nuevo, como si lo acabara de instanciar.

Ejemplo 27.79. Ejemplo del método reset()

// Build this query:
//   SELECT p.*
//   FROM "products" AS p
//   ORDER BY "product_name"

$select = $db->select()
             ->from(array('p' => 'products')
             ->order('product_name');

// Changed requirement, instead order by a different columns:
//   SELECT p.*
//   FROM "products" AS p
//   ORDER BY "product_id"

// Clear one part so we can redefine it
$select->reset( Zend_Db_Select::ORDER );

// And specify a different column
$select->order('product_id');

// Clear all parts of the query
$select->reset();