Crear consulta paso a través con postgresql

Estoy utilizando access como frontend con postgresql como backend esto para que me puedan entender mejor, tengo la siguiente tabla.

 

Quiero crear una consulta de Paso a Través al servidor de datos PostgreSQL, para obtener en una columna el monto del siguiente período de acuerdo con el grupo, el rango del período se toma de un formulario.

Por ejemplo, si en el formulario elijo el rango del período entre 2018 y 2020, el resultado de la consulta de paso a través debe ser algo parecido a lo siguiente.

Aunque no me sirven las funciones de dominio de Access, porque no son tablas vinculadas, también quisiera conocer cómo se puede hacer la consulta en Access.

Agradezco la solución o idea que me puedan brindar.

2 Respuestas

Respuesta
2

Primero que todo lo felicito Hernán por utilizar PostgreSQL como Back End, es un gran acierto. La instrucción que explican le sobra un paréntesis en And (Year(fecha)<2020 y NO es la respuesta porque la información ya está agrupada por idgrupo y fecha, lo que solicitan es "... obtener en una columna el monto del siguiente período de acuerdo con el grupo". Asumo por esto se hace en PostgreSQL por la dificultad.

Lo primero que debe realizar es hacer la consulta en PostgreSQL y probarla, si es correcta se copia para insertarla en el código de VBA.

CONSULTA EN POSTGRESQL

Explicación de la consulta en PostgreSQL:

Para agrupar por año es necesario obtener el año del campo fecha, esto lo hago con la función extract(year from fecha). Retorna 2018, 2019 etc

LEAD proporciona acceso a una fila que sigue a la fila actual en un desplazamiento físico especificado

OVER determina exactamente cómo se dividen las filas de la consulta para que las procese la función de ventana.

PARTITION BY pertenece a la categoría Funciones de ventana. Las funciones de ventana de PostgreSQL son las que son capaces de realizar cálculos que abarcan varias filas de una columna, pero no todas las filas.

ORDER BY permite ordenar por el año, igualmente se debe convertir el campo fecha. Se había podido crear una función en PostgreSQL para pasar la fecha como parámetro y obtener el año.

RESULTADO EN POSTGRESQL

AHORA EN ACCESS

FORMULARIO

Hago clic en Crear Query y obtengo

CÓDIGO DEL BOTÓN CREAR QUERY
Private Sub btn_2_Click()
 Dim strQuery As String
 strQuery = "qryComparaPorGruposPeriodos"
 If (Not (IsNull(Me.cboDesde) And IsNull(Me.cboHasta))) And Me.cboDesde < Me.cboHasta Then
  Call CreaQueryComparaPorGruposPeriodos(strQuery, Val(Me.cboDesde), Val(Me.cboHasta))
  DoCmd.OpenQuery strQuery
 End If
End Sub

CÓDIGO DE LA FUNCIÓN

Public Function CreaQueryComparaPorGruposPeriodos(SPTQueryName As String, intDesde As Integer, intHasta As Integer)
'En este ejemplo se utiliza la función para obtener en una columna
'el monto del año siguiente en un rango de años por grupos
'Requiere referenciar a:
'                       Microsfot ActiveX Data Objectc 6.1 Library
'                       Microsfot ADO Ext. 6.0 for DLL and Security
'Fuente:
'    Microsoft
'Adpatación para PostgreSQL
'Eduardo Pérez Fernández
'Fecha: 13/09/2022
'Parametros:
'               SPTQueryName  --> Nombre de la consulta a crear
'               intDesde ---> Año inicial
'               intHasta ---> Año final
 On Error GoTo hay_Error
Dim cat As ADOX.Catalog
Dim cmd As ADODB.Command
Dim strSQl As String
Dim tB As DAO.TableDef
Dim MyQueryDef As QueryDef
With CurrentDb
  For Each MyQueryDef In CurrentDb.QueryDefs
   If MyQueryDef.Name = SPTQueryName Then
   .QueryDefs.Delete (SPTQueryName)
   .QueryDefs.Refresh
   Exit For
   End If
  Next
End With
Set cat = New ADOX.Catalog
Set cmd = New ADODB.Command
cat.ActiveConnection = CurrentProject.Connection
Set cmd.ActiveConnection = cat.ActiveConnection
  strSQl = "SELECT   idgrupo,extract(year from fecha) as mperiodo " & vbCrLf
  strSQl = strSQl & "           ,   monto" & vbCrLf
  strSQl = strSQl & "           ,  LEAD(monto,1) OVER (PARTITION BY idgrupo     " & vbCrLf
  strSQl = strSQl & "    ORDER BY extract(year " & vbCrLf
  strSQl = strSQl & "        FROM fecha) ) ventas_sgte_periodo " & vbCrLf
  strSQl = strSQl & "        FROM  ventas " & vbCrLf
  strSQl = strSQl & "       WHERE extract(year " & vbCrLf
  strSQl = strSQl & "        FROM fecha) BETWEEN " & intDesde & " AND " & intHasta & ";"
  cmd.CommandText = strSQl
  cmd.Properties("Jet OLEDB:ODBC Pass-Through Statement") = True
cmd.Properties _
     ("Jet OLEDB:Pass Through Query Connect String") = _
       "ODBC;DSN=dbconta;"
  cat.Procedures.Append SPTQueryName, cmd
  Set cat = Nothing
  Set cmd = Nothing
hay_Error_Exit:
   Exit Function
hay_Error:
    MsgBox "Ocurrió el error " & Err.Number & vbCrLf & vbCrLf & Err.Description, vbCritical, "Error..."
    Resume hay_Error_Exit
End Function

Y no dejará de resultar quien opine que no es eficiente utilizar PostgreSQL con Access en bases de datos "pequeñas", supuestamente por el rendimiento.  

El código SQL para Access es correcto, pero es bastante lento en tablas de gran tamaño, hasta el punto de colapsar. Ahora, ¿qué pasa si cambia el rango de fechas? Se debe adicionar en Año, algo como

WHERE Grupo1.Año Between 2019 And 2020

Aunque el código de Access se puede utilizar en PostgreSQL con algunos cambios NI se le ocurra utilizarlo. Déjelo para Access mientras le funcione en bases de datos pequeñas.

Respuesta
1

... Aunque no me sirven las funciones de dominio de Access, porque no son tablas vinculadas, también quisiera conocer cómo se puede hacer la consulta en Access.


En Access no se utilizarían funciones de dominio, se utilizaría una consulta de datos agrupados, se agrupa por año e idgrupo y se suma el monto:

SELECT idgrupo, Year(fecha) AS Año, Sum(monto) AS Resultado FROM Tabla0001 GROUP BY Year(fecha),idgrupo HAVING Year(fecha)>=2018 And (Year(fecha)<2020

Antes de nada: mis disculpas por no haber leído el hilo con atención y completo, la respuesta correcta para obtener ese resultado en Access es esta:

SELECT Grupo1.Idgrupo, Grupo1.Año, Grupo1.mperiodo, Grupo2.ventasSigPeriodo
FROM (SELECT Year([Fecha]) AS Año, Tabla4.Idgrupo, Tabla4.monto AS mperiodo
FROM Tabla4) as Grupo1  LEFT JOIN (SELECT Year([Fecha])-1 AS año2, Tabla4.Idgrupo, Tabla4.Monto AS ventasSigPeriodo
FROM Tabla4) as Grupo2  ON (Grupo1.Año = Grupo2.año2) AND (Grupo1.Idgrupo = Grupo2.Idgrupo)
ORDER BY Grupo1. Idgrupo, Grupo1. Año;

Se parte de un conjunto de datos (tabla4) que como tal conjunto de datos puede ser local o externo, sea en PosgreSQL, SqlServer, MySQl o MariaDb ... o cualquier otro, simplemente hace falta tener acceso a los datos para tratarlos.

Eduardo:

Los datos publicados parecen un resumen del cual se pretende obtener esa presentación así que de colapsar algo no sería Access y menos con esa SQL.

Los años se obtienen del conjunto de datos del que se parte (le es indiferente cuales y cuantos son los años para el cálculo).

Por otra parte:
Si tan inmenso es el volumen de datos (digamos que a nivel mundial la producción hortícola por metro cuadrado plantado) creo que ni Access ni con PostgreSQL serían las herramientas adecuadas (y esa particular metodología de trabajo sea en Access o en combinación con PostgreSQL tampoco sería la óptima).

Que (según has publicado) hubieras tenido una mala experiencia con datos en Access (generalmente el error suele provocarlo el usuario por inexperiencia o descuido), no hace a PostgreSQL la mejor base de datos del mundo (solo existiría esa y no es así).

Así que: 'Al Cesar lo que es del Cesar y a Dios lo que es de Dios'.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas