Mostrando entradas con la etiqueta Consulta. Mostrar todas las entradas
Mostrando entradas con la etiqueta Consulta. Mostrar todas las entradas

2016-07-11

Ordenar registros en Access de manera personalizada

Title

Problema

Queremos ordenar los registros de una consulta de manera personalizada. En nuestro ejemplo usamos la base de datos Neptuno. Deseamos ordenar los registros de la tabla Pedidos con un orden personalizado basado en el País de destinatario.

Solución

  1. Creamos una tabla de búsqueda. En la columna Orden establecemos el que deseamos.
  2. Creamos una consulta en la que unimos por el campo común la tabla creada TablaPaís con la tabla Pedidos que deseamos ordenar.
  3. Añadimos el campo Orden en la consulta, especificamos en Orden Ascendente y desmarcamos la selección Mostrar.
  4. Ejecutamos la consulta.

Resultados

Los registros aparecerán en el orden especificado en la tabla de búsqueda TablaPaís: México, Irlanda, Reino Unido, Brasil, etc.

2015-08-11

Porcentaje del total de la columna mediante subconsulta en Ms Access

Title

Problema

Queremos calcular el porcentaje del total de la columna mediante subconsulta. Anteriormente vimos como calcular el porcentaje del total de la columna mediante la función DSuma.

Partimos de la siguiente tabla sacada de la anterior entrada.

Solución

  • En SQL
  • SELECT Tabla1.x, Tabla1.freq, [freq]/(SELECT Sum(Tabla1.freq) FROM Tabla1) AS prob
    FROM Tabla1
    GROUP BY Tabla1.x, Tabla1.freq;
    
  • En Access
  • Creamos la siguiente consulta.

    1. Añadimos los dos campos x y freq
    2. En la ficha Diseño, en el grupo Mostrar u ocultar, clic en Totales (símbolo del sumatorio, sigma).
    3. Campo calculado prob con la expresión en la que introducimos la subconsulta:
    4. prob: [freq]/(SELECT Sum(Tabla1.freq) FROM Tabla1)
      
  • Resultado
  • Para mostrar el formato anterior, estándar con 4 decimales, en la hoja de propiedades del campo prob seleccionamos las propiedades mencionadas.

    Referencias

    2015-03-13

    Consulta SQL en Excel mediante Microsoft ActiveX Data Objects (ADO)

    Title En Excel podemos tratar una hoja como una tabla de datos y crear consultas SQL mediante Microsoft ActiveX Data Objects (ADO). Aunque presenta ciertas limitaciones, puede resultar de utilidad en algunas ocasiones:

    Evitamos conectar Excel con Access.
    Evitamos crear un tabla dinámica intermedia.

    Ejemplo

    1. Descargamos el libro Tablas Neptuno.
    2. Creamos una hoja de destino, que nombramos como Destination, donde irán los resultados.
    3. Abrimos el editor de Visual Basic y en el menú de Herramientas clic en referencias añadimos: Microsoft ActiveX Data Objects 6.0 Library.
    4. Insertamos un módulo en el que añadimos el siguiente código.
    5. Sub Excel_QueryTable()
      
          Sheets("Destination").Cells.ClearContents
          
          Dim oCn As ADODB.Connection
          Dim oRS As ADODB.Recordset
          Dim ConnString As String
          Dim SQL As String
          
          Dim qt As QueryTable
          
          ' Cadena de conexión
          ConnString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
              & ThisWorkbook.Path & "\" & ThisWorkbook.Name & _
              ";Extended Properties=Excel 8.0;Persist Security Info=False"
          Set oCn = New ADODB.Connection
          oCn.ConnectionString = ConnString
          oCn.Open
      
          ' Consulta en SQL
          SQL = "SELECT [Ciudad], [País] FROM [Clientes$]" & _
                "GROUP BY [Ciudad], [País]"    
          
          Set oRS = New ADODB.Recordset
          oRS.Source = SQL
          oRS.ActiveConnection = oCn
          oRS.Open
      
          ' Hoja de destino
          Set qt = Sheets("Destination").QueryTables.Add(Connection:=oRS, _
          Destination:=Sheets("Destination").Range("A1"))
          
          qt.Refresh       
          
          If oRS.State <> adStateClosed Then
          oRS.Close
          End If
          
          If Not oRS Is Nothing Then Set oRS = Nothing
          If Not oCn Is Nothing Then Set oCn = Nothing
      
      End Sub
      
    6. Ejecutamos la subrutina
    7. Guardamos el fichero como *.xlsm si queremos conservar el código.

    Resultado

    El resultado en la hoja de destino serán 70 registros con sus encabezados de columna.

    Notas

    • Es necesario especificar el nombre de las hojas entre corchetes y con el símbolo dolar al final de la misma: [Clientes$]
    • A menos que la hoja activa sea la hoja de destino, es necesarios especificar explícitamente la misma:

       Set qt = Sheets("Destination").QueryTables.Add(Connection:=oRS, _
          Destination:=Sheets("Destination").Range("A1"))
    • Empleamos una QueryTable en lugar de copyfromrecordset para obtener los encabezados de las columnas. Si no, emplearíamos en lugar de qt:
    • Sheets("Destination").Range("A1").CopyFromRecordset oRS

    Referencias

    2015-01-28

    Ley de Benford en Ms Access

    Title La ley de Benford, también conocida como la ley del primer dígito, se refiere a la frecuencia de distribución del primer dígito en muchos de los números que aparecen en la vida real. En esta distribución, el 1 aparece con una frecuencia aproximada del 30% mientras que el 9 aparece con una frecuencia menor del 5%. Por primer dígito se refiere al primer dígito no nulo o significativo.

    Esta ley se puede aplicar a una gran variedad de fuentes de datos: facturas de electricidad, direcciones de calles, precios de acciones, cifras de población, tasas de mortalidad, longitud de los ríos o constantes físicas y matemáticas. Se ha aplicado en la detección de fraudes en contabilidad, resultados electorales y científicos.

    Ejemplo

    Queremos calcular la frecuencia relativa del campo Cargo de la tabla Pedidos de la base de datos Neptuno. El resultado final es una tabla con los dígitos, su frecuencia absoluta, el total de registros y la frecuencia porcentual.

    Solución 1

    En dos pasos:

    1. Consulta intermedia (qry_Total): calcula el total de registros de la tabla cuyo último dígito del campo Cargo es mayor que cero.
    2. SELECT COUNT(Pedidos.Cargo) AS Total
      FROM Pedidos
      WHERE (((Mid([Cargo],1,1))>0));
      
    3. Consulta final (qry_BenfordLaw) que calcula la frecuencia relativa usando el total de la consulta anterior.

    SELECT Mid([Cargo],1,1) AS Dígito, 
    COUNT(Pedidos.Cargo) AS Frecuencia, 
    qry_Total.Total, 
    COUNT([Pedidos]![Cargo])/[Total] AS Porcentaje
    FROM Pedidos, qry_Total
    GROUP BY Mid([Cargo],1,1), qry_Total.Total
    HAVING (((Mid([Cargo],1,1))>0));
    

    Solución 2

    Creando una subconsulta evitando la consulta intermedia.

    SELECT Mid([Cargo],1,1) AS Dígito, 
    COUNT(Pedidos.Cargo) AS Frecuencia, 
    (select count([Cargo]) FROM Pedidos WHERE (((Mid([Cargo],1,1))>0))) AS Total, 
    Count([Pedidos]![Cargo])/[Total] AS Porcentaje
    FROM Pedidos
    GROUP BY Mid([Cargo],1,1)
    HAVING (((Mid([Cargo],1,1))>0));
    
    La subconsulta es idéntica a la consulta intermedia (qry_Total) que realizamos en la solución 1.

    (SELECT COUNT([Cargo]) FROM Pedidos WHERE (((Mid([Cargo],1,1))>0))) AS Total
    

    Referencias

    2015-01-18

    Mensaje de error en Access: no se pudo eliminar nada en las tablas especificadas

    Title Cuando queremos realizar una consulta de eliminación que emplea varias tablas puede aparecer el siguiente mensaje de error: No se pudo eliminar nada en las tablas especificadas.

    Ejemplo

    Empleamos la base de datos Neptuno y creamos una consulta de eliminación con las tablas Detalles de pedidos y Pedidos. Queremos eliminar todos aquellos pedidos, y sus detalles, que contengan al menos un producto con descuento.

    Al ejecutar la consulta Access muestra el mensaje:

    Solución

    1. Abrimos la hoja de propiedades de la consulta.
    2. Establecemos la propiedad Registros únicos en Sí.
    3. Ejecutamos la consulta de nuevo

    Resultado

    Elimina 380 registros de la tabla Pedidos y quedan 450 pedidos con productos sin ningún descuento. Además, habremos eliminado 1.045 registros de la tabla Detalles de pedidos. Esto es debido a que en las relaciones entre ambas tablas están activadas la casillas Exigir integridad referencial y Eliminar en cascada los registros relacionados. Access elimina automáticamente todos los registros que hacen referencia a la clave principal (IdPedido) al eliminarse el registro que contiene la clave principal.

    En la tabla Detalles de pedidos quedan 1.110 productos. Cuando mostramos la consulta en modo Ver nos muestra los 838 registros que tienen algún descuento. Pero al ejecutar la consulta también borra aquellos productos de pedidos que contienen algún producto descontado (comparten el mismo IdPedido): 1.045.

    Explicación

    Instrucción SQL de la consulta antes de cambiar la propiedad de Registros únicos a No.

    DELETE Pedidos.*, [Detalles de pedidos].Descuento
    FROM Pedidos INNER JOIN [Detalles de pedidos] ON Pedidos.IdPedido = [Detalles de pedidos].IdPedido
    WHERE ((([Detalles de pedidos].Descuento)>0));
    Instrucción SQL de la consulta antes de cambiar la propiedad de Registros únicos a Sí.

    DELETE DISTINCTROW Pedidos.*, [Detalles de pedidos].Descuento
    FROM Pedidos INNER JOIN [Detalles de pedidos] ON Pedidos.IdPedido = [Detalles de pedidos].IdPedido
    WHERE ((([Detalles de pedidos].Descuento)>0));
    Al establecer la propiedad Registros únicos en Sí, Access añade DISTINCTROW al predicado de la consulta SQL. En nuestro ejemplo, la tabla Pedidos no contiene registros duplicados de IdPedido, pero la tabla Detalles de pedidos sí, pues cada pedido incluye diferentes productos. Al indicar DISTINCTROW genera una lista de pedidos única con al menos un registro en Detalles de pedidos. Si omitimos DISTINCTROW genera varias filas para cada una de los pedidos que tengan más de un registro en Detalles de pedido.

    Referencias

    2014-11-14

    Añadir criterios adicionales para el mismo campo en una consulta de Ms Access

    Title Un compañero de trabajo me planteó el siguiente problema hace unos días.Todas las filas de criterios en la cuadrícula de diseño estaban ocupadas y quería añadir nuevos criterios. Es una consulta muy básica pero que puede surgir a usuarios principiantes.

    He recreado el ejemplo con una nueva consulta en modo de diseño en la que añadimos la tabla Pedidos de la base de datos Neptuno y filtramos una serie de países.

    Alternativas

    1. Insertamos más filas para añadir más criterios. en el grupo Configuración de consultas de la pestaña Diseño, clic en Insertar filas.

    2. Incluimos más criterios en una misma fila añadiendo el operador O entre cada criterio.

    Si las expresiones están en filas diferentes de la cuadrícula de diseño, Access utiliza el operador O, que indica que se devolverán los registros que cumplan los criterios de cualquiera de las celdas.

    Por tanto en lugar de utilizar diferentes filas, podemos introducir en una misma fila criterios adicionales separados por el operador O.

    3. Abrimos la consulta en vista SQL y la modificamos. Conviene recordar que cada consulta ejecuta SQL en segundo plano. La vista diseño de Access sirve para construir con una interfaz gráfica una consulta sin necesidad de escribir SQL.

    SELECT Pedidos.PaísDestinatario, Sum(Pedidos.Cargo) AS SumaDeCargo
    FROM Pedidos
    GROUP BY Pedidos.PaísDestinatario
    HAVING (((Pedidos.PaísDestinatario)="Alemania")) OR (((Pedidos.PaísDestinatario)="Argentina")) OR (((Pedidos.PaísDestinatario)="España")) OR (((Pedidos.PaísDestinatario)="México")) OR (((Pedidos.PaísDestinatario)="Portugal")) OR (((Pedidos.PaísDestinatario)="Venezuela"))OR
    (((Pedidos.PaísDestinatario)="Finlandia")) ;
    
    
    Al volver a la vista diseño, Access habrá agrupado el contenido en la primera fila de Criterios, tal y como vimos en la imagen del punto 2.

    2014-08-03

    Consultas combinadas en SQL y Ms Access (join queries)

    Title En esta entrada explicaremos las consultas combinadas (join queries). Se denominan así porque combinan filas de dos o más tablas. También explicaremos cómo realizar estas consultas en Ms Access, que utiliza un dialecto de SQL conocido como Jet SQL que presenta algunas diferencias en la sintaxis y expresiones con la versión estándar de SQL.

    Nota importante:

    Como un abundante número de entradas en la red, explicamos las consultas combinadas mediante diagramas de Venn (usados en teoría de conjuntos). Estos diagramas sirven solamente como analogía y no representan con exactitud el resultado de las consultas combinadas cuando no hay una relación de uno a uno entre las tablas. Cuando la relación entre las tablas es de uno a varios, o de varios a varios, la representación es inadecuada. En estos casos tenemos un nuevo conjunto de filas que satisface las condiciones de la combinación, que no están en ninguna de las tablas, pero que contiene la combinación de columnas de ambas tablas.

    Como ejemplo he usado dos tablas empleadas en la wikipedia para explicar estas consultas: tabla employee (empleado) y la tabla department (departamento).

    Todos las columnas: * = employee.LastName, employee.DepartmentID, department.DepartmentName

    Cross join

    Es un producto cartesiano de las dos tablas. Es decir, todas las combinaciones posibles entre las filas de las dos tablas.

    SELECT *
    FROM department 
    CROSS JOIN employee;
    
    Access no permite el comando CROSS JOIN. Por tanto el código anterior generaría un error. Para evitar el error en Access usamos una cross join implícita:

    SELECT *
    FROM employee, department;
    
    En general, su uso está fuertemente desaconsejado por su capacidad para generar un número enorme de filas. Mil filas en dos tablas generarían un millón de registros. Sin embargo, controladamente son útiles para obtener todas las combinaciones posibles o para crear bases de datos de prueba rápidamente.

    Inner join

    Compara cada fila de la tabla A (employee) con cada fila de la tabla B (department) para encontrar todos los pares de filas que satisfacen dichas condiciones especificadas.

    ON o WHERE preceden la condiciones especificadas.

    El diagrama de Venn no ilustra adecuadamente el resultado de la consulta y nos puede conducir a equívoco. El gráfico indica que nuestro conjunto incluirá la intersección de elementos de ambas tablas. Sin embargo, el resultado de la tabla inferior incluye un nuevo conjunto de filas que no pertenecen ni a la tabla A ni a la B. Este nuevo conjunto incluye las columnas de A y B con aquellas filas de ambas tablas que cumplen la condición especificada, que tengan un DepartmentID idéntico. Para cada empleado con el employee.DepartmentID igual al department.DepartmentID las columnas de ambas tablas. Los departamentos Engineering y Clerical aparecen dos veces pues hay dos empleados en la tabla A (employee) que pertenecen a dichos departamentos.

    SELECT *
    FROM employee 
    INNER JOIN department
    ON department.DepartmentID = employee.DepartmentID;
    
    Inner join implícita

    SELECT *
    FROM employee, department
    WHERE employee.DepartmentID = department.DepartmentID;
    

    Left outer join

    Devuelve todas las filas de la tabla A (employee) incluso si no encuentra ninguna fila en la tabla B (department) que satisfaga la condiciones especificadas. Dicho de otra manera, incluye los resultados de la inner join más aquellas filas de la tabla A (employee) que no coinciden con las de la tabla B (department).

    SELECT *
    FROM employee 
    LEFT JOIN department 
    ON employee.DepartmentID = department.DepartmentID;
    

    Left outer join excluyendo la inner join

    SELECT *
    FROM employee 
    LEFT JOIN department 
    ON employee.DepartmentID = department.DepartmentID
    WHERE department.DepartmentID Is Null;
    
    Right y left outer joins son funcionalmente equivalentes. Ambas proporcionan la misma funcionalidad, de manera que cualquiera de ellas puedes ser reemplazada con la otra con tal de que se invierta el orden de las tablas.

    Consulta anterior planteada como una right join (su inversa)

    SELECT *
    FROM department 
    RIGHT JOIN employee 
    ON department.DepartmentID = employee.DepartmentID;
    

    Right outer join

    Es la consulta inversa de la left outer join. Tan sólo se invierte el orden de las tablas. Devuelve todas las filas de la tabla B (department) incluso si no encuentra ninguna fila en la tabla A (employee) que satisfaga la condiciones especificadas. Dicho de otra manera, incluye los resultados de la inner join más aquellas filas de la tabla B (department) que no coinciden con las de la tabla A (employee).

    El diagrama de Venn no representa adecuadamente el resultado de la consulta y nos puede conducir a equívoco. El gráfico nos dice que nuestro conjunto incluirá solamente las filas de la tabla B. Sin embargo, el resultado de la tabla inferior no incluye solamente las 4 filas de la tabla B (department), sino aquellas filas de ambas tablas que cumplen la condición especificada. Muestra cada departamento de la tabla B tantas veces como empleados en la tabla A pertenezcan al mismo. Los departamentos Engineering y Clerical aparecen dos veces pues hay dos empleados en la tabla A (employee) que pertenecen a dichos departamentos.

    SELECT *
    FROM employee 
    RIGHT JOIN department 
    ON employee.DepartmentID = department.DepartmentID;
    
    Consulta anterior planteada como una left join (su inversa)

    SELECT *
    FROM department 
    LEFT JOIN employee 
    ON employee.DepartmentID = department.DepartmentID;
    

    Right outer join excluyendo la inner join

    SELECT *
    FROM employee 
    RIGHT JOIN department 
    ON employee.DepartmentID = department.DepartmentID
    WHERE employee.DepartmentID Is Null;
    

    Full outer join

    Devolverá todas filas de ambas tablas A (employee) y B (department), satisfagan o no las condiciones especificadas. Para aquellos registros que cumplan las condiciones especificadas devolverá una sola fila con los valores correspondientes de cada tabla.

    SELECT *
    FROM employee 
    FULL OUTER JOIN department
    ON employee.DepartmentID = department.DepartmentID;
    
    Ms Access no permite el uso del comando FULL OUTER JOIN. Para obtener el mismo resultado empleamos UNION:

    Full outer join = left outer join + right inner join

    SELECT *
    FROM employee 
    LEFT JOIN department 
    ON employee.DepartmentID = department.DepartmentID
    
    UNION 
    
    SELECT *
    FROM employee 
    RIGHT JOIN department 
    ON employee.DepartmentID = department.DepartmentID;
    
    Otra alternativa es:

    Full outer join = left outer join excluyendo la inner join + inner join + right inner join excluyendo la inner join

    SELECT *
    FROM employee 
    LEFT JOIN department 
    ON employee.DepartmentID = department.DepartmentID
    WHERE department.DepartmentID Is Null
    
    UNION 
    
    SELECT *
    FROM employee 
    INNER JOIN department 
    ON department.DepartmentID = employee.DepartmentID
    
    UNION
    
    SELECT *
    FROM employee 
    RIGHT JOIN department 
    ON employee.DepartmentID = department.DepartmentID
    WHERE (((employee.DepartmentID) Is Null));
    
    Full outer join excluyendo la inner join

    SELECT *
    FROM employee 
    FULL OUTER JOIN department
    ON employee.DepartmentID = department.DepartmentID
    WHERE employee.ID IS null
    OR department.ID IS null;
    
    Como Ms Access no permite el uso del comando FULL OUTER JOIN:

    Full outer join = left outer join excluyendo la inner join + right inner join excluyendo la inner join

    SELECT *
    FROM employee 
    LEFT JOIN department 
    ON employee.DepartmentID = department.DepartmentID
    WHERE department.DepartmentID Is Null
    
    UNION 
    
    SELECT *
    FROM employee 
    RIGHT JOIN department 
    ON employee.DepartmentID = department.DepartmentID
    WHERE employee.DepartmentID Is Null;
    

    Referencias

    2013-08-26

    Consulta para generar una muestra aleatoria en Ms Access

    Title En la entrada anterior vimos como generar números aleatorios con la función NúmAleat. Con esa función podemos generar una muestra aleatoria de nuestros datos.

    Creamos una consulta, agregamos los campos deseados, en el ejemplo todos los campos de TuTabla.* Añadimos un campo con la función NúmAleat basado en un campo numérico de la tabla, ordenamos por este campo, seleccionamos en Devuelve: el número de registros de la muestra o porcentaje del total y ejecutamos la consulta.

    En SQL, la sintaxis sería:

    SELECT TOP 100 TuTabla.*
    FROM TuTabla
    ORDER BY Rnd([campo numérico]);
    Si solamente tuviéramos campos de texto, usamos la función Longitud (Len en inglés) para que nos devuelva como valor el número de caracteres de la cadena de texto. La consulta sería:
    En SQL:

    SELECT TOP 100 TuTabla.*
    FROM TuTabla
    ORDER BY Rnd(Len([campo de texto]));
    

    Es importante señalar que la función NúmAleat con un argumento igual a cero devuelve el último número generado. Y si es negativo, repite cada vez el mismo número aleatorio para ese valor.

    La solución sería usar la función Abs, que devuelve el valor absoluto de un número:
    NúmAleat(Abs([campo numérico]))

    En SQL:

    SELECT TOP 100 TuTabla.*
    FROM TuTabla
    ORDER BY Rnd(Abs([campo numérico]));

    Otra alternativa sería usar de nuevo la función Longitud como vimos más arriba, en este caso con un campo numérico. Así forzamos a que nos devuelva un número mayor que cero,  aunque tenga un cero o un número negativo.

    En SQL:

    SELECT TOP 100 TuTabla.*
    FROM TuTabla
    ORDER BY Rnd(Len([campo numérico]));

    Entradas relacionadas

    Nube de datos