Sei sulla pagina 1di 25

CURSO DE SQL

CAPTULO 31

ndice de contenido
COMPLIQUEMOS UN POCO LAS CONSULTAS DE SELECCIN..............................................2
VAMOS ALL................................................................................................................................2
CREACIN DE LITERALES.....................................................................................................2
UTILIZACIN DE ALIAS.........................................................................................................3
ALIAS DIRECTO COMO CAMPO..........................................................................................3
ALIAS DIRECTO COMO TABLA............................................................................................4
ALIAS INDIRECTO: USO DE FUNCIONES AGREGADAS.................................................5
OPERACIONES MATEMTICAS Y OTRAS POSIBILIDADES..................................6
FUNCIONES DE VALORES SIMPLES...............................................................................7
ABS().................................................................................................................................8
SQR().................................................................................................................................8
MOD()...............................................................................................................................8
ROUND()..........................................................................................................................8
FUNCIONES DE GRUPOS DE VALORES (FUNCIONES DE AGREGADO)..................8
COUNT()...........................................................................................................................8
SUM()................................................................................................................................9
AVG()................................................................................................................................9
STDEV() / STDEVP().......................................................................................................9
FIRST() / LAST()............................................................................................................10
MAX() / MIN()................................................................................................................10
CONSULTAS ANIDADAS, O SUBCONSULTAS...........................................................................10
UTILIZANDO IN......................................................................................................................10
UTILIZANDO ANY/SOME..................................................................................................12
UTILIZANDO EXISTS.............................................................................................................12
COMBINACIN DE ELEMENTOS EN SQL..................................................................................13
COMBINACIN EXTERNA (O LLMAME... OUTER JOINS)...........................................13
CORRESPONDENCIA CON LAS CONSULTAS-OBJETO EN ACCESS. TIPOS DE
COMBINACIN......................................................................................................................15
COMBINACIN INTERNA (O LLMAME... INNER JOIN)...............................................16
CONSULTA UNION / UNION ALL.....................................................................................17
CONSULTA TRANSFORM......................................................................................................19
AUTOCOMBINACIN................................................................................................................21
SELF JOIN....................................................................................................................................22
CLUSULA HAVING...................................................................................................................24
PARA FINALIZAR ESTE CAPTULO.............................................................................................25
1

La BD donde estn los ejemplos de este captulo os la podis bajar aqu.

Vistame en http://siliconproject.com.ar/neckkito/

COMPLIQUEMOS UN POCO LAS CONSULTAS DE SELECCIN


VAMOS ALL...
Vamos a seguir con nuestras consultas de seleccin, las
cuales vamos a complicar un poco (pero no mucho!).
Aprenderemos, en este apartado, a realizar algunas
acciones interesantes para obtener valores que no estn,
directamente, en las tablas, para pasar de lleno a la
utilizacin de funciones agregadas de SQL.
Os recuerdo que la BD de ejemplo con la que trabajaremos es la misma que creamos en el
captulo 1, y con la que ya trabajamos en el captulo 2.
Y, como se indica en el ttulo de este epgrafe, vamos all...!

CREACIN DE LITERALES
Puede interesarnos, en un momento dado, mostrar una informacin puntual a travs de una
consulta, e identificar claramente qu informacin estamos obteniendo.
Para estos casos podemos hacer uso de literales.
Un literal no es ms que una cadena de texto que nos mostrar el valor literal que hayamos
escrito en cada registro de la consulta.
La estructura para un literal podra ser la siguiente:
SELECT nomTabla.nomCampo1, 'Literal', nomTabla.nomCampo2
FROM nomTabla
Supongamos que queremos ver las ventas, pero con impuestos incluidos, y que nuestro
impuesto es el 18%. Para no perder de vista que estamos trabajando con valores impuesto
incluido podramos querer que en cada registro se mostrara dicha informacin.
Nuestro cdigo con la SQL pertinente sera el siguiente:

Private Sub cmdLiteral_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CLiteral"
Call eliminaConsulta(nomQuery)
miSql = "SELECT TVentas.IdCliVta, 'Ventas impuesto incluido: ', TVentas.ImpVta*1.18" _
& " FROM TVentas"

Call creaConsulta(nomQuery, miSql)


DoCmd.OpenQuery nomQuery
End Sub

Obtendramos el siguiente resultado:

Vistame en http://siliconproject.com.ar/neckkito/

Fijaos que, aunque no sea una solucin muy elegante, para una consulta puntual nos puede
sacar del apuro.
Tambin cabe destacar que podemos realizar operaciones matemticas con los valores de los
registros directamente sobre la SQL. En nuestro caso hemos multiplicado por 1,18:
TVentas.ImpVta*1.18

UTILIZACIN DE ALIAS
En ocasiones puede interesarnos crear un campo que no existe inicialmente en la tabla. Esta
creacin puede ser realizada de dos maneras:

De manera directa
De manera indirecta, porque aplicamos alguna funcin.

Y qu es un alias? Para que nos entendamos, es el nombre que nos inventamos para poder
hacer referencia a ese campo que no existe, inicialmente.
Supongo que, hasta ahora, la cosa est clara (o no?). La verdad es que sin ver un ejemplo
este concepto puede parecer un poco difuso. Vamos pues a plantear una hiptesis de trabajo
para la creacin de un alias de manera directa.

ALIAS DIRECTO COMO CAMPO


Imaginemos que el jefe de ventas quiere repasar, sobre papel, las ventas realizadas durante el
ao 2011. Como es algo no oficial le basta que le imprimamos los resultados de una consulta
con la finalidad de que l pueda puntear dichas ventas.
Evidentemente podramos crear una consulta como ya sabemos e imprimirla, pero como
queremos quedar bien con el jefe vamos a crearle un campo ms a la consulta, en blanco, y
que adems la columna est identificada con el ttulo Punteado.
Para ello vamos a crearnos una SQL que utilizar un alias, y ese alias ser precisamente el
texto Punteado.
Nuestro cdigo sera, entonces:

Vistame en http://siliconproject.com.ar/neckkito/


Private Sub cmdAliasPunteado_Click()
Dim miSql As String, nomQuery As String
nomQuery = "CAliasPunteado"
Call eliminaConsulta(nomQuery)
miSql = "SELECT TVentas.IdCliVta, TVentas.ImpVta, NULL AS Punteado" _
& " FROM TVentas" _
& " WHERE TVentas.FechVta>#12-31-2011#"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Obtendramos el siguiente resultado:

Como vemos, del cdigo podramos sacar varias conclusiones:

Para definir el alias utilizamos la palabra reservada AS, y la estructura es:


<valor/expresin> AS <alias>

El campo que hace de filtro NO tiene porqu mostrarse en los resultado (filtramos por
fecha de venta pero no se ve en la consulta)

Para indicar que queremos un campo vaco utilizamos NULL


Es decir, que si nuestro jefe se pone tonto y dice que quiere la palabra NO para poder l ir
tachndola nuestra SQL debera quedar:
miSql = "SELECT TVentas.IdCliVta, TVentas.ImpVta, 'NO' AS Punteado" _
& " FROM TVentas" _
& " WHERE TVentas.FechVta>#12-31-2011#"

ALIAS DIRECTO COMO TABLA


Por comodidad para escribir la SQL podramos utilizar un alias sobre el nombre de la tabla en
la que estamos trabajando.
4

Vistame en http://siliconproject.com.ar/neckkito/

Para comodidad de lectura de cdigo podemos utilizar AS, aunque en el caso de tablas
podemos poner el alias directamente, sin necesidad de utilizar el AS.
Por ejemplo, el siguiente cdigo utiliza un alias sobre la
tabla:

Private Sub cmdAliasTabla_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CAliasTabla"
Call eliminaConsulta(nomQuery)
miSql = "SELECT TV.IdCliVta, TV.ImpVta, 'NO' AS Punteado" _
& " FROM TVentas AS TV" _
& " WHERE TV.FechVta<=#12-31-2011# AND TV.ImpVta>8000"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Si nos fijamos hemos definido el alias sobre la tabla tras la clusula FROM, a travs de ( FROM
TVentas AS TV), y todas las referencias a nomTabla han sido hechas con TV.
Si hubiramos escrito nuestra SQL as (fijaos lo escrito tras el FROM) nuestra SQL funcionara
igualmente bien:
miSql = "SELECT TV.IdCliVta, TV.ImpVta, 'NO' AS Punteado" _
& " FROM TVentas TV" _
& " WHERE TV.FechVta<=#12-31-2011# AND TV.ImpVta>8000"

ALIAS INDIRECTO: USO DE FUNCIONES AGREGADAS


La expresin alias indirecto la utilizo slo a efectos de seguir un hilo argumental para el
captulo, dado que en el fondo un alias es un alias. La diferencia entre directo e indirecto
estriba, en realidad, en si asignamos directamente algn valor al alias (ya sea NULL o ya sea
una cadena de texto o un nmero) o no asignamos valor alguno (al definir un alias para una
tabla), o si el valor del alias se obtiene de manera indirecta al realizar alguna operacin
matemtica o lgica o a travs de la utilizacin de funciones agregadas.
Hago tambin esta separacin a efectos pedaggicos, porque pienso que la sistemtica del
alias se entiende mejor si realizamos esta categorizacin.
Quera hacer esta aclaracin porque dudo que si alguien busca informacin por ah sobre este
tema pueda encontrar estos trminos de alias directo o alias indirecto (o, al menos, yo he
sido incapaz de encontrar algo parecido). Hay que ser originales, verdad?
Clarificado lo anterior vamos a ver este tema de funciones agregadas, pero antes, para hacer
este apartado ms completo, veremos el uso de operaciones matemticas y otras
posibilidades.
5

Vistame en http://siliconproject.com.ar/neckkito/

OPERACIONES MATEMTICAS Y OTRAS POSIBILIDADES


Podemos realizar operaciones matemticas en la propia SQL
y asignarles un alias. Por ejemplo, nos acordamos de
nuestra SQL de Ventas al 18%, unas pginas antes?
Vamos a hacer lo mismo, pero desglosando el impuesto y el
total final, utilizando alias para cada uno de ellos.
Si estructuramos un poco lo que sera una posible SQL,
veremos que la parte correspondiente al impuesto podra
ser:
TVentas.ImpVta*0.18 As Impuesto
y para la parte correspondiente al total tenemos dos posibilidades:
.- Una, realizar la operacin matemtica directamente sobre el importe de la venta:
TVentas.ImpVta*1.18
.- O bien utilizar la suma de dos campos: el existente (ImpVta) y el alias que acabamos
de crear (Impuesto):
(TVentas.ImpVta + Impuesto) AS ImpConImpto
En definitiva, nuestro cdigo podra quedarnos de la siguiente manera:

Private Sub cmdVtasImpto_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CVtasImpto"
Call eliminaConsulta(nomQuery)
miSql = "SELECT TVentas.IdCliVta, TVentas.ImpVta," _
& " TVentas.ImpVta*0.18 AS Impuesto, (TVentas.ImpVta+Impuesto) AS ImpConImpto" _
& " FROM TVentas"

'-----Esta otra SQL tambin conseguira lo mismo----------------------------------------' miSql = "SELECT TVentas.IdCliVta, TVentas.ImpVta," _
'
& " TVentas.ImpVta*0.18 AS Impuesto, TVentas.ImpVta*1.18 AS ImpConImpto" _
'
& " FROM TVentas"
'---------------------------------------------------------------------------------------Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Importante: recordad que para operar con exponentes debemos utilizar el smbolo (^),

siguiendo la estructura (valor^exponente). Para conseguir ese smbolo debemos localizar la


tecla que est a la derecha de la P y pulsar la combinacin SHIFT+tecla, y a continuacin
pulsar la barra espaciadora. Por ejemplo, para hallar el cubo de 25 escribiramos: 25^3
Supongamos que necesitamos un campo donde se muestren, juntos, apellido, nombre de los
trabajadores.
6

Vistame en http://siliconproject.com.ar/neckkito/

Para conseguir eso debemos recurrir al concatenador ampersand (&), y construirnos la


estructura del campo como la deseamos, para despus asignarle un alias.
Es decir, que nuestro cdigo para hacer lo anterior sera:

Private Sub cmdApellNombre_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CApellNom"
Call eliminaConsulta(nomQuery)
miSql = "SELECT (TTB.ApellTrab & ', ' & TTB.NomTrab) AS Empleado," _
& " TTB.CIFTrab FROM TTrabPersonal AS TTB"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Si nos fijamos, veremos que hemos construido el campo a travs de la estructura:


<tabla.campo1> & <', '> & <tabla.campo2>
(TTB.ApellTrab & ', ' & TTB.NomTrab)
Tambin, para no tener que escribir cada vez el largo nombre de la tabla, he utilizado un
alias sobre la tabla.

FUNCIONES DE VALORES SIMPLES


Vamos a ver una serie de funciones que podemos utilizar con SQL. Las dividiremos en
funciones de valores simples, es decir, funciones que operan sobre un solo valor, de las
siguientes, que son las que operan sobre grupos de valores.
El cdigo genrico que utilizaremos para explicar estas funciones ser el siguiente:

Private Sub cmdAbs_Click()


Dim miSql As String, nomQuery As String
nomQuery = "NombreConsulta"
Call eliminaConsulta(nomQuery)
miSql = <SQL mostrada en cada apartado>
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Si queremos practicar, slo deberemos copiar el anterior cdigo, sustituyendo lo marcado en


7

Vistame en http://siliconproject.com.ar/neckkito/

negrita.
As, en los siguientes epgrafes slo os mostrar lo que debera ser
la SQL.

ABS()
Devuelve el VALOR ABSOLUTO de un nmero. En la tabla de
ejemplo no se van a producir variaciones en el resultado
porque no hay valores negativos, pero, si los hubiera,
quedaran convertidos en valores positivos.
miSql = "SELECT Abs(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"

SQR()
Devuelve la RAZ CUADRADA de un valor.
miSql = "SELECT Sqr(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"

MOD()
Devuelve el RESTO DE LA DIVISIN de un valor entre otro valor.
La SQL muestra el resto de dividir el importe de las ventas entre cinco
miSql = "SELECT (TVentas.ImpVta MOD 5) As Resultado" _
& " FROM TVentas"

ROUND()
La funcin Round() REDONDEA LOS DECIMALES DE UN VALOR AL NMERO DE DECIMALES
QUE INDICAMOS, siguiendo la estructura:
Round(<valor>,<n de decimales>)
La siguiente SQL redondea los decimales del importe de ventas a un solo decimal.
miSql = "SELECT Round(TVentas.ImpVta,1) As Resultado" _
& " FROM TVentas"

FUNCIONES DE GRUPOS DE VALORES (FUNCIONES DE AGREGADO)


Estas funciones operan sobre un grupo de registros y devuelven un slo registro de resultado.
Echmosles un vistazo.

COUNT()
Esta funcin devuelve la CUENTA de los registros.
Si queremos saber cuntos registros cumplen la condicin de que las ventas sean superiores a
8

Vistame en http://siliconproject.com.ar/neckkito/

5000 euros nuestra SQL sera:

miSql = "SELECT Count(*) As Resultado" _


& " FROM TVentas" _
& " WHERE TVentas.ImpVta>=5000"

SUM()
Devuelve la SUMA de los valores seleccionados.
Si queremos saber el total de ventas realizadas tendramos:
miSql = "SELECT Sum(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"

AVG()
Devuelve el PROMEDIO de los valores seleccionados.
As, el promedio de todas las ventas sera:
miSql = "SELECT Avg(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"
VAR() / VARP()
La funcin Var() devuelve la VARIANZA DE UNA MUESTRA DE POBLACIN; la funcin Varp()
devuelve la VARIANZA DE UNA POBLACIN.
La SQL sera (ejemplo con Var(); con Varp() la estructura sera la misma):
miSql = "SELECT Var(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"

STDEV() / STDEVP()
La funcin Stdev() devuelve la DESVIACIN ESTNDAR DE UNA MUESTRA DE POBLACIN; la
funcin Stdevp() devuelve la DESVIACIN ESTNDAR DE UNA POBLACIN.
La SQL sera (ejemplo con StDev(); con StDevp() la estructura sera la misma):
miSql = "SELECT Stdev(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"

Vistame en http://siliconproject.com.ar/neckkito/

FIRST() / LAST()
First() devuelve el valor DEL PRIMER REGISTRO; Last() devuelve el valor DEL LTIMO
REGISTRO.

Las SQL seran:


miSql = "SELECT First(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"
--miSql = "SELECT Last(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"

MAX() / MIN()
Max() devuelve el valor MXIMO de un grupo de registros; Min() devuelve el valor MNIMO de
un grupo de registros.
La siguiente SQL nos muestra la venta mayor de las que se han realizado:
miSql = "SELECT Max(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"
y la siguiente nos muestra la venta ms pequea que se ha conseguido:
miSql = "SELECT Min(TVentas.ImpVta) As Resultado" _
& " FROM TVentas"

CONSULTAS ANIDADAS, O SUBCONSULTAS


En ocasiones puede sernos til realizar una subconsulta para filtrar los datos de una consulta
principal. Y tambin, en algunos casos, podran existir mtodos alternativos para conseguir el
mismo resultado.
Sin embargo, es interesante saber que existe esta sistemtica de trabajo con las SQL, y que
podemos utilizarlas.

UTILIZANDO IN
Planteemos el problema: queremos saber el detalle del importe de las ventas realizadas por los
clientes (hasta aqu ya deberamos saber hacerlo), pero slo de los clientes que estn en las
poblaciones de Badajoz y Cdiz.
Bueno, bueno... primer problema que tenemos: las ventas estn en una tabla y las poblaciones
10

Vistame en http://siliconproject.com.ar/neckkito/

estn en otra.
Si operramos con la consulta como objeto de Access con
toda probabilidad sabramos cmo hacerlo: aadiramos
ambas tablas, las relacionaramos por su identificador y
filtraramos por los valores que queremos.
La anterior operacin la podramos realizar utilizando la
operacin INNER JOIN (que veremos ms adelante). Pero
en este apartado vamos a realizar una subconsulta para
conseguir el mismo efecto.
Vayamos por partes, empezando por detrs:
Si quisiramos realizar una SQL que nos filtrara los clientes de Badajoz y Cdiz, cogiendo su
identificador de cliente, escribiramos:
miSql = "SELECT TClientes.IdCli FROM TClientes" _
& " WHERE TClientes.PoblCli IN ('Badajoz','Cdiz')"
Y esto ya lo sabemos hacer.
La anterior consulta nos devuelve los valores {2,5,10}
Para construir la SQL principal podramos pues escribir:
miSql = "SELECT TVentas.IdCliVta, TVentas.ImpVta FROM TVentas" _
& " WHERE TVentas.IdCliVta IN (2,5,10)
Estamos de acuerdo?
Pues bsicamente se trata de sustituir los valores por la consulta que nos proporciona esos
valores.
Es decir, que nuestro cdigo nos quedara as:

Private Sub cmdSubconsultas_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CSubconsulta"
Call eliminaConsulta(nomQuery)
miSql = "SELECT TVentas.IdCliVta, TVentas.ImpVta FROM TVentas" _
& " WHERE TVentas.IdCliVta IN (" _
& "SELECT TClientes.IdCli FROM TClientes" _
& " WHERE TClientes.PoblCli IN ('Badajoz','Cdiz'))"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Slo llamar la atencin sobre el hecho de que no debemos olvidarnos el parntesis de cierre
del IN () de la consulta principal.

11

Vistame en http://siliconproject.com.ar/neckkito/

UTILIZANDO ANY/SOME
Los predicados ANY o SOME son sinnimos, por lo que
podemos emplear tanto uno como otro. Se utilizan como
comparadores de los resultados que devuelve la
subconsulta.
Por ejemplo, imaginemos que queremos ver una lista con
todos los datos de los clientes que han realizado compras
durante el ao 2011. Nuestra SQL podra quedar de la
siguiente manera:

Private Sub cmdSubconsultas2_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CSubconsulta2"
Call eliminaConsulta(nomQuery)
miSql = "SELECT * FROM TClientes" _
& " WHERE TClientes.IdCli= ANY (" _
& "SELECT TVentas.IdCliVta FROM TVentas" _
& " WHERE TVentas.FechVta<#01-01-12#)"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Si utilizramos el predicado ALL en lugar de ANY obtendramos un resultado en el cual los


registros de la consulta principal satisfacen la comparacin con todos los registros obtenidos de
la subconsulta.

UTILIZANDO EXISTS
Con el predicado EXISTS lo que obtenemos es un TRUE o FALSE; es decir, comprobamos si la
subconsulta nos dice S o No.
Por ejemplo, queremos saber qu clientes NO han realizado ninguna compra durante el ao
2011. Ser nuestra subconsulta la que nos dir si s han realizado compra o no, y la consulta
principal nos mostrar los resultados:

Private Sub cmdSubconsulta3_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CSubconsulta3"
Call eliminaConsulta(nomQuery)
miSql = "SELECT * FROM TClientes" _
& " WHERE NOT EXISTS (" _
& "SELECT * FROM TVentas" _
& " WHERE (TVentas.FechVta<#01-01-12# AND" _
& " TClientes.IdCli=TVentas.IdCliVta))"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub
12

Vistame en http://siliconproject.com.ar/neckkito/


Fijaos en que:
Para saber si el cliente existe hemos tenido que indicar la
correspondencia del identificador de cliente, necesario para
que la SQL funcione
(& " Tclientes.IdCli=TVentas.IdCliVta))")

Para indicar que NO EXISTE hemos utilizado NOT


(NOT EXISTS). Si no ponemos el NOT obtendramos los que
S han realizado compras durante 2011.

COMBINACIN DE ELEMENTOS EN SQL


En este apartado vamos a ver cmo podemos combinar elementos de la misma o de distintas
tablas en una sola consulta.

COMBINACIN EXTERNA (O LLMAME... OUTER JOINS)


En SQL podemos encontrar dos tipos de Outer Join:

LEFT OUTER JOIN


RIGHT OUTER JOIN

La estructura de una OUTER JOIN sera, en general, la siguiente:


SELECT
FROM tabla1 LEFT/RIGHT OUTER JOIN tabla2
ON <condicin de relacin entre campos de tablas>
Y qu es un Outer Join? Os pego lo que el propio Access dice sobre el tema:
<<La combinacin externa (OUTER JOIN) se utiliza para recuperar registros de varias tablas mientras se conservan
los registros de una de las tablas, aun cuando en la otra no haya ningn registro que coincida. El motor de base de
datos de Access admite dos tipos de combinaciones externas: LEFT OUTER JOIN (izquierda) y RIGHT OUTER
JOIN (derecha). Imagine dos tablas situadas una junto a otra, una a la izquierda y otra a la derecha. La LEFT
OUTER JOIN selecciona todas las filas de la tabla derecha que cumplen los criterios de comparacin relacionales,
adems de seleccionar todas la filas de la tabla izquierda, aun cuando no existan coincidencias en la tabla derecha. La
RIGHT OUTER JOIN es sencillamente lo contrario de la LEFT OUTER JOIN: en ella se conservan todas las filas
de la tabla derecha>>
A ver si con un ejemplo clarificamos lo anterior. La finalidad de nuestra consulta: mostrar todos
los clientes dados de alta en nuestra BD (a travs de TClientes) y la suma de las ventas
realizadas para cada uno de ellos.
Y qu pasa si hay algn cliente al que an no se le ha vendido nada? Pues no hay problema,
porque:

TClientes ser nuestra tabla de la izquierda

Utilizaremos LEFT OUTER JOIN

En consecuencia, nos mostrar TODOS los registros de TClientes, aunque no haya


ventas realizadas a algn cliente.
Es decir, que si programamos la siguiente SQL:

13

Vistame en http://siliconproject.com.ar/neckkito/


Private Sub cmdOuterJoins_Click()
Dim miSql As String, nomQuery As String
nomQuery = "COuterJoins"
Call eliminaConsulta(nomQuery)
miSql
&"
&"
&"

= "SELECT TClientes.IdCli, TClientes.NomCli, Sum(TVentas.ImpVta) As Ventas" _


FROM TClientes LEFT OUTER JOIN TVentas" _
ON TClientes.IdCli = TVentas.IdCliVta" _
GROUP BY TClientes.IdCli, TClientes.NomCli"

Call creaConsulta(nomQuery, miSql)


DoCmd.OpenQuery nomQuery
End Sub

El resultado que obtendremos ser el siguiente:

Como podemos apreciar, a Rbanos Buenitos an no se le ha efectuado ninguna venta, por lo


que el cliente nos aparece, pero con un valor NULL en la columna Ventas.
Un par de comentarios sobre el cdigo:

Hemos utilizado una funcin de agregado (Sum())


Por ello, debemos agrupar los campos que queremos mostrar mediante un GROUP BY

Si no lo hiciramos as obtendramos un error. Supongamos que en nuestra SQL nos olvidamos


de agrupar por NomCli, de manera que la ltima lnea de la SQL fuera:
& " GROUP BY TClientes.IdCli"

Si intentamos ejecutar el cdigo obtendramos el siguiente error:


14

Vistame en http://siliconproject.com.ar/neckkito/

Conclusin: si obtenemos este error debemos comprobar nuestro GROUP BY


Slo nos queda comentar que podemos omitir la palabra OUTER y Access seguir entendiendo
que queremos realizar una combinacin externa. Es decir, que si en el anterior cdigo
hubiramos escrito:
miSql = "SELECT TClientes.IdCli, TClientes.NomCli, Sum(TVentas.ImpVta) As Ventas" _
& " FROM TClientes LEFT JOIN TVentas" _
& " ON TClientes.IdCli = TVentas.IdCliVta" _
& " GROUP BY TClientes.IdCli, Tclientes.NomCli"
la consulta nos hubiera funcionado perfectamente.

CORRESPONDENCIA CON LAS CONSULTAS-OBJETO EN ACCESS.


TIPOS DE COMBINACIN
Como supongo todo el mundo sabr (y si no lo sabe pues lo aprenderemos ahora... no
problem) existen tres tipos de combinaciones en una relacin entre dos tablas en una
consulta-objeto de Access:

Combinacin tipo 1: la consulta devuelve slo los registros coincidentes en ambas


tablas.

Combinacin tipo 2: la consulta devuelve todos los registros de la tabla de la izquierda,


y slo los coincidentes de la tabla de la derecha

Combinacin tipo 2: la consulta devuelve todos los registros de la tabla de la derecha, y


slo los coincidentes de la tabla de la izquierda.
Cuando realizamos una consulta en vista diseo entre dos tablas relacionadas Access utiliza la
combinacin tipo 1 por defecto. Vemoslo:
.- Creamos una consulta en vista diseo sobre las tablas TClientes y TVentas.
Automticamente se nos debera crear una relacin entre ambas a travs de los campos [IdCli]
e [IdCliVta]

15

Vistame en http://siliconproject.com.ar/neckkito/

.- Nos situamos sobre la lnea de relacin y, con mucho pulso, hacemos click con el botn de la
derecha. Nos saldr un men contextual con dos opciones:

.- Si seleccionamos la opcin Propiedades de la


combinacin veremos que, por defecto, tenemos marcada
la combinacin tipo 1, pudiendo cambiar la combinacin a
tipo 2 o tipo 3

Llegados aqu, si seleccionamos:

La combinacin tipo 2 estaremos realizando una LEFT OUTER JOIN


La combinacin tipo 3 estaremos realizando una RIGHT OUTER JOIN
La combiancin tipo 1 estaremos realizando un INNER JOIN

Y, en consecuencia, vamos a ver la relacin INNER JOIN a continuacin.

COMBINACIN INTERNA (O LLMAME... INNER JOIN)


Como hemos visto anteriormente, una combinacin INNER JOIN devuelve slo los registros
coincidentes.
La estructura de este tipo de consultas, en general, sera:
SELECT
FROM tabla1 INNER JOIN tabla2
ON <condicin de relacin entre campos de tablas>
Siguiendo con el ejemplo anterior, si convertimos la consulta que hemos hecho en una INNER
JOIN obtendramos:

Private Sub cmdInnerJoin_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CInnerJoin"
Call eliminaConsulta(nomQuery)

16

Vistame en http://siliconproject.com.ar/neckkito/

miSql = "SELECT TClientes.IdCli, TClientes.NomCli, Sum(TVentas.ImpVta) As


Ventas" _
& " FROM TClientes INNER JOIN TVentas" _
& " ON TClientes.IdCli = TVentas.IdCliVta" _
& " GROUP BY TClientes.IdCli, TClientes.NomCli"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Es decir, que no nos aparecer la empresa


correspondencia con ningn registro en TVentas.

Rbanos

Buenitos

porque

no

tiene

CONSULTA UNION / UNION ALL


Podemos combinar una o varias tablas para la consecucin del resultado que nos interese a
travs de una consulta de UNION.
La estructura de una consulta de Unin sera, para que nos entendemos, la unin de dos
consultas SELECT a travs de la operacin UNION.
SELECT FROM
UNION
SELECT FROM
Por ejemplo, supongamos que queremos obtener una consulta que nos devuelva los clientes
con ventas superiores a 15000 euros y tambin los clientes con ventas inferiores a 2000,
descartando los valores intermedios, podramos realizar la siguiente consulta de unin:

Private Sub cmdUnion_Click()


Dim miSql As String, nomQuery As String
17

Vistame en http://siliconproject.com.ar/neckkito/

nomQuery = "CUnion"
Call eliminaConsulta(nomQuery)

miSql
&"
&"
&"
&"

= "SELECT TVentas.IdCliVta, TVentas.ImpVta FROM TVentas" _


WHERE TVentas.ImpVta>=15000" _
UNION" _
SELECT TVentas.IdCliVta, TVentas.ImpVta FROM TVentas" _
WHERE TVentas.ImpVta<=2000"

Call creaConsulta(nomQuery, miSql)


DoCmd.OpenQuery nomQuery
End Sub

Si analizamos el cdigo, veremos que las dos primeras lneas


conforman una SQL de seleccin que ya sabemos construir sin
problemas, lo mismo que las dos ltimas lneas. Entre ambas hemos
aadido la operacin UNION para conseguir la informacin prevista.
Podemos realizar una consulta de unin entre dos tablas tambin,
aunque la estructura deber ser consistente. Por poner un ejemplo
absurdo (o no... de todo hay en este mundo) imaginemos que queremos conseguir un listado
de empresas clientes y de trabajadores. Podramos crear una consulta de unin entre
TTrabPersonal y TClientes. Por ejemplo, nuestra consulta podra ser:

Private Sub cmdUnion2_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CUnion2"
Call eliminaConsulta(nomQuery)
miSql
&"
&"
&"

= "SELECT (TTrabPersonal.NomTrab & ' ' & TTrabPersonal.ApellTrab) AS Listado" _


FROM TTrabPersonal" _
UNION" _
SELECT TClientes.NomCli FROM TClientes"

Call creaConsulta(nomQuery, miSql)


DoCmd.OpenQuery nomQuery
End Sub

Como vemos he tenido que crear un campo que me uniera el nombre del trabajador y su
apellido porque el nombre de la empresa corresponde slo a un campo, no a dos; en definitiva,
lo que os comentaba de conseguir una estructura consistente.
Para saciar vuestra segura curiosidad, aqu tenis capturado un fragmento de lo que devolvera
la anterior consulta:

18

Vistame en http://siliconproject.com.ar/neckkito/

Os copio aqu algunas indicaciones que da la propia ayuda de Access sobre este tipo de
consultas que creo que pueden seros tiles:
<<De forma predeterminada, no se devuelven registros duplicados cuando se usa la operacin UNION; sin embargo,
puede incluir el predicado ALL para asegurarse de que se devuelven todos los registros. Adems, de esta manera, la
consulta se ejecuta ms rpidamente.
Todas las consultas de una operacin UNION deben solicitar el mismo nmero de campos; sin embargo, no es
necesario que los campos sean del mismo tamao o tipo de datos.
Use alias slo en la primera instruccin SELECT, ya que en las dems se omiten. En la clusula ORDER BY, haga
referencia a los campos por el nombre que se utilice en la primera instruccin SELECT.>>
Y, para acabar, tened en cuenta que las consultas de unin NO ADMITEN el uso de campos tipo
hipervnculo, objeto OLE o Datos Adjuntos. Si los intentis utilizar el campo os saldr con
#ERROR

CONSULTA TRANSFORM
Una SQL con la instruccin TRANSFORM es lo que en Access conocemos como consulta de
referencias cruzadas
La estructura en general de una SQL con TRANSFORM sera:
TRANSFORM
<funcin de agregado>
SELECT FROM
GROUP BY
PIVOT
Vamos a ver cmo aplicamos lo anterior para construirnos una SQL. Lo haremos razonndolo
porque este tipo de consulta, para quienes la ven por primera vez, puede parecer muy
complicada, aunque no tiene por qu serlo.
Imaginemos que queremos ver la suma por clientes y por meses, correspondientes al ao
2012. Quedmonos con este enunciado, pues ser el hilo conductor para realizar la SQL.
Hemos dicho que queremos ver la suma de las ventas. Esto ya nos da el primer elemento de
la SQL. Y como contiene una funcin de agregado (suma) ser lo primero que escribiremos en
la SQL. As:
TRANSFORM
Sum(TVentas.ImpVta) As Ventas

19

Vistame en http://siliconproject.com.ar/neckkito/

Sigamos:
Cul es el criterio de la vista que queremos obtener? Pues el criterio es por clientes y por
meses.
Vamos a por el primer criterio. Necesitamos los clientes...
pues vamos a seleccionarlos:
SELECT TVentas.IdCliVta FROM TVentas
pero vamos a necesitar un filtro, porque slo queremos
incluir las ventas del ao 2012. Pues sigamos como si
construyramos una SQL filtrada:
WHERE TVentas.FechVta>=#01-01-12#
Recordamos qu ocurra cuando utilizbamos una funcin de agregado? Pues lo
comentbamos en el apartado anterior Combinacin externa, con el error 3122. As que... a
agrupar
GROUP BY TVentas.IdCliVta
Y vamos a por el segundo criterio. Queremos la informacin por meses. Y para sacar el mes de
una fecha utilizamos la funcin Datepart() -eso deberamos saberlo de VB, pero si no lo
sabemos lo aprendemos aqu... sin problemas-. Y la funcin Datepart(), para que nos devuelva
el mes, tiene la siguiente sintaxis: Datepart('m',<campo con la fecha>).
Si seguimos la estructura indicada en el comienzo de este apartado escribiramos pues:
PIVOT Datepart('m',TVentas.FechVta)
A que no es tan difcil? (Espero que respondis con un S unnime...!).
Nuestro cdigo quedara as:

Private Sub cmdTransform_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CTransform"
Call eliminaConsulta(nomQuery)
miSql
&"
&"
&"
&"

= "TRANSFORM sum(TVentas.ImpVta) AS Ventas" _


SELECT TVentas.IdCliVta FROM TVentas" _
WHERE TVentas.FechVta>=#01-01-12#" _
GROUP BY TVentas.IdCliVta" _
PIVOT Datepart('m',TVentas.FechVta)"

Call creaConsulta(nomQuery, miSql)


DoCmd.OpenQuery nomQuery
End Sub

Y la consulta nos devolvera la siguiente informacin:

20

Vistame en http://siliconproject.com.ar/neckkito/

AUTOCOMBINACIN
Supongamos que queremos obtener una informacin que pase por combinar elementos que
tenemos dentro de la propia tabla y que, de alguna manera, dependen los unos de los otros.
Para realizar la autocombinacion vamos a servirnos de la misma tabla pero, gracias a un alias,
vamos a tratarlas cmo si fueran dos tablas distintas.
Por ejemplo, vamos a ver una consulta que nos devolver el empleado con su cargo junto con
el nombre del empleado del que depende, tambin con su puesto.
A la tabla de empleados (que saldr de TTrabLaboral) le pondremos el alias Empl, y a la tabla
de superiores (que tambin saldr de TTrabLaboral) le pondremos el alias Sup.
Nuestro cdigo quedara as:

Private Sub cmdAutocombinacion_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CAutocombinacion"
Call eliminaConsulta(nomQuery)
miSql = "SELECT Empl.IdTrab, Empl.Cargo, Sup.IdTrab, Sup.Cargo" _
& " FROM TTrabLaboral AS Empl, TTrabLaboral AS Sup" _
& " WHERE Empl.DependeDe=Sup.IdTrab"
Call creaConsulta(nomQuery, miSql)
DoCmd.OpenQuery nomQuery
End Sub

Fijmonos cmo:

Hemos utilizado dos alias sobre la misma tabla, de manera que parece que
manejamos dos tablas diferentes (TTrabLaboral AS Empl, TTrabLaboral AS Sup)
Hemos seleccionado los campos que nos interesaban seleccionndolos como si fueran
campos de esas dos tablas diferentes (SELECT Empl.IdTrab, Empl.Cargo,
Sup.IdTrab, Sup.Cargo)
Para obtener la relacin hemos utilizado datos que tenemos en la misma tabla, y que
provienen
de
los
campos
[IdTrab]
y
[DependeDe]
(WHERE
Empl.DependeDe=Sup.IdTrab)

Y como resultado obtenemos una consulta tan hermosa como la siguiente:

21

Vistame en http://siliconproject.com.ar/neckkito/

SELF JOIN
Para conseguir un producto cartesiano de una tabla consigo misma podemos utilizar una
estructura SELF JOIN. Un producto cartesiano establece una relacin de cada uno de los
elementos de la tabla por s mismo y por el resto de elementos de la tabla.
Para poder poner un ejemplo de SELF JOIN vamos a tener que crearnos una nueva tabla, que
llamaremos TRepresentantes. Esta tabla nos recoger los clientes y los responsables dentro del
departamento de ventas que se encargan de ellos (tranquilos: haremos el ejemplo con pocos
registros).
La estructura de la tabla ser la siguiente:

Teniendo en cuenta que en el campo [IdCliRepr] el tipo de datos viene dado por el asistente
para bsquedas, donde hemos seleccionado la tabla TClientes y como campo visible [NomCli[,
y que para el campo [IdTrabRepr] el tipo de datos se ha creado utilizando el asistente para
bsquedas, donde hemos seleccionado de la tabla TTrabPersonal y como campos visibles
[ApellTrab] y [NomTrabl] (por este orden).
Rellenamos la tabla con unos pocos datos. Yo la he rellenado as:

Es decir, que nuestra empresa siempre asigna dos representantes para cada cliente, para
poderse cubrir las vacaciones (porque en nuestra empresa S damos vacaciones )
Vamos a realizar la misma operacin que en el apartado anterior; es decir, vamos a dividir
nuestra tabla en dos utilizando un alias.
El cdigo para una combinacin SELF JOIN sobre esta tabla podra ser:

22

Vistame en http://siliconproject.com.ar/neckkito/


Private Sub cmdSelfJoin_Click()
Dim miSql As String, nomQuery As String
nomQuery = "CSelfJoin"
Call eliminaConsulta(nomQuery)
miSql
&"
&"
&"

= "SELECT Uno.IdCliRepr, Uno.IdTrabRepr, Dos.IdTrabRepr" _


FROM TRepresentantes AS Uno, TRepresentantes AS Dos" _
WHERE Uno.IdCliRepr = Dos.IdCliRepr" _
AND Uno.IdTrabRepr > Dos.IdTrabRepr"

Call creaConsulta(nomQuery, miSql)


DoCmd.OpenQuery nomQuery
End Sub

Y obtenemos:

Como podemos ver, a una hipottica tabla la hemos llamado Uno, y a la otra Dos, y las
hemos relacionado a travs de (Uno.IdCliRepr = Dos.IdCliRepr). Si nos hubiramos
quedado aqu (sin aadir el AND) tendramos una SELF JOIN en toda regla. Es decir, que nos
saldra el producto cartesiano puro y duro. Para los incrdulos...

En nuestro ejemplo no tena mucho sentido la informacin Filemn-Filemn, o SecretoSecreto, o Secreto-Zape/Zape-Secreto. Para eliminar estos duplicados hemos aadido el
AND, que los elimina.
23

Vistame en http://siliconproject.com.ar/neckkito/

CLUSULA HAVING
La clusula HAVING tiene un comportamiento muy parecido
al WHERE, pero trabaja con grupos de registros (WHERE no
puede trabajar con grupos de registros). Hablando para que
nos entendamos, WHERE nos muestra un conjunto de filas
que cumplen un criterio como campos individuales, y
HAVING nos muestra grupos de registros que cumplen un
criterio como grupo de registros.
Y, como hablamos de grupos, no podemos olvidarnos de utilizar el GROUP BY con HAVING.
Vamos a desgranar un ejemplo con lo anterior.
Imaginemos que queremos obtener una consulta de los totales de ventas, pero que nos
muestre slo aquellos totales que sean mayores que un lmite que hemos establecido como
objetivo de ventas, que ser de 8.500 euros.
Debemos crear pues una primera agrupacin, que ser la que nos calcular la suma de las
ventas agrupadas por cliente.
SELECT TVentas.IdCliVta, Sum(TVentas.ImpVta) AS VentasTotales FROM TVentas
GROUP BY TVentas.IdCliVta
Con esta primera agrupacin ya tenemos los totales de todas las ventas, pero ahora queremos
realizar un filtrado sobre ese grupo, de manera que slo nos muestre aquellos registros (que,
recordemos, estn formados por la agrupacin por suma de registros individuales) que
cumplen nuestra condicin.
Para ello deberamos agregar dicho filtro sobre grupo, es decir, HAVING
HAVING Sum(TVentas.ImpVta)>=8500
Si combinamos todo lo anterior en una SQL obtendramos:

Private Sub cmdHaving_Click()


Dim miSql As String, nomQuery As String
nomQuery = "CHaving"
Call eliminaConsulta(nomQuery)
miSql
&"
&"
&"

= "SELECT TVentas.IdCliVta, Sum(TVentas.ImpVta) AS VentasTotales" _


FROM TVentas" _
GROUP BY TVentas.IdCliVta" _
HAVING Sum(TVentas.ImpVta)>=8500"

Call creaConsulta(nomQuery, miSql)


DoCmd.OpenQuery nomQuery
End Sub

Como curiosidad, para rematar este apartado, os dir que, segn Microsoft, una clusula
HAVING puede contener hasta 40 expresiones vinculadas por operadores lgicos, como AND y
OR.

24

Vistame en http://siliconproject.com.ar/neckkito/

PARA FINALIZAR ESTE CAPTULO


Creo que con este captulo ya tenemos abundante material
para poder realizar unas SQL alucinantes en nuestras BD's

Slo quisiera recalcar que, lgicamente, por motivos


pedaggicos hemos visto apartado por apartado diferentes
elementos, operaciones y dems que podemos utilizar con
SQL. No perdis de vista que todo lo anterior se puede
combinar en una enorme SQL, que, por decirlo
poticamente, vendr limitada por las caractersticas del
propio lenguaje SQL y por nuestra imaginacin.
Espero que todo lo anterior os pueda ser de utilidad.
Un saludo, y...
suerte!

25

Vistame en http://siliconproject.com.ar/neckkito/

Potrebbero piacerti anche