¿Cómo puedo obtener de una tabla el segundo registro de un grupo?

Señores expertos, tengo la siguiente tabla en Excel que pasado a Access:

Me exigen obtener de acuerdo con el idseccion ordenado por sueldo de mayor a menor el nombre del segundo registro del grupo. Explico mejor con la siguiente imagen.

La solución me sirve en Excel, Access o PostgreSQL.

3 respuestas

Respuesta
1

¿El resultado esperado será algo cómo?

Si exactamente necesito obtener los 3 registros.

Martha le preparado los ejemplos en Access y PostgreSQL, Excel no lo recomiendo para este tipo de consultas, no obstante, excelente la respuesta de Dante (Un saludo).

EN ACCESS

Hago clic sobre el botón Obtiene Segundo del Grupo y obtengo la siguiente consulta

Código del botón

Private Sub btnSegundo_Click()
 On Error GoTo hay_error
  Dim strSQl As String
 '   Requiere de la función:
 '       RT_NumerarParcialSQL()
 '   Autor JESUS MANSILLA CASTELLS -Mihura-
  'Verifico si existe la tabla
    If DCount("[Name]", "MSysObjects", "[Name] = 'temgrupos'") = 1 Then
        DoCmd.DeleteObject acTable, "temgrupos"
    End If
   'Verifico si existe la consulta
    If DCount("[Name]", "MSysObjects", "[Name] = 'qryGrupos'") = 1 Then
        DoCmd.DeleteObject acQuery, "qryGrupos"
    End If
  strSQl = "SELECT tblempleados.idempleado" & vbCrLf
  strSQl = strSQl & "           , tblempleados.idseccion" & vbCrLf
  strSQl = strSQl & "           , tblempleados.empleado" & vbCrLf
  strSQl = strSQl & "           , tblempleados.sueldo" & vbCrLf
  strSQl = strSQl & "           , RT_NumerarParcialSQL([idseccion]) AS cons INTO temgrupos" & vbCrLf
  strSQl = strSQl & "        FROM tblempleados" & vbCrLf
  strSQl = strSQl & "    ORDER BY tblempleados.idseccion" & vbCrLf
  strSQl = strSQl & "           , tblempleados.sueldo DESC;"
  CurrentDb.Execute strSQl
  strSQl = "SELECT temgrupos.idempleado" & vbCrLf
  strSQl = strSQl & "           , temgrupos.idseccion" & vbCrLf
  strSQl = strSQl & "           , temgrupos.empleado" & vbCrLf
  strSQl = strSQl & "           , temgrupos.sueldo" & vbCrLf
  strSQl = strSQl & "        FROM temgrupos" & vbCrLf
  strSQl = strSQl & "       WHERE temgrupos.cons=2" & ";"
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = CurrentDb()
Set qdf = db.CreateQueryDef("qryGrupos", strSQl)
' Abre la consulta y muéstrala
DoCmd.OpenQuery qdf.Name, acViewNormal
' Libera la memoria
Set qdf = Nothing
Set db = Nothing
hay_error_Exit:
  Exit Sub
hay_error:
    MsgBox "Ocurrió el error " & Err.Number & vbCrLf & Err.Description, vbCritical, "Error"
    Resume hay_error_Exit
End Sub

Función  RT_NumerarParcialSQL()

Public Function RT_NumerarParcialSQL(nDato) As Long
'variable que no se pierde entre las distintas llamadas
Static nCONTADOR As Long, nANTERIOR As String
     If IsNull(nDato) Then 'si nDato es nulo: Iniciamos valor
         nCONTADOR = 0
         nANTERIOR = ""
         Exit Function
     End If
     '- si nDato es igual al valor memorizado sumamos 1 al contador
     If nDato = nANTERIOR Then
         nCONTADOR = nCONTADOR + 1
       Else '- iniciamos valor y memorizamos el anterior
         nCONTADOR = 1
         nANTERIOR = nDato
     End If
     RT_NumerarParcialSQL = nCONTADOR
End Function
Public Function RT_NumerarParcialSQL(nDato) As Long
'variable que no se pierde entre las distintas llamadas
Static nCONTADOR As Long, nANTERIOR As String
     If IsNull(nDato) Then 'si nDato es nulo: Iniciamos valor
         nCONTADOR = 0
         nANTERIOR = ""
         Exit Function
     End If
     '- si nDato es igual al valor memorizado sumamos 1 al contador
     If nDato = nANTERIOR Then
         nCONTADOR = nCONTADOR + 1
       Else '- iniciamos valor y memorizamos el anterior
         nCONTADOR = 1
         nANTERIOR = nDato
     End If
     RT_NumerarParcialSQL = nCONTADOR
End Function

Puede cambiar el 2 por otro número, en este caso sería mejor elaborar una función con este código y pasar el número como parámetro.

EN POSTGRESQL (Mi preferido)

SELECT idempleado,empleado,idseccion ,sueldo
FROM (
  SELECT idempleado,empleado,idseccion, sueldo, 
    DENSE_RANK() OVER (PARTITION BY idseccion ORDER BY sueldo DESC) as rnk
  FROM tblempleados
) As t
WHERE t.rnk = 2
ORDER BY t.idseccion;

Observe la potencia y la simplicidad del script en comparación con Access y por su puesto con Excel.

Resultado de la consulta en PostgreSQL

Si le tiene alguna duda la puede hacer a mi correo [email protected] 

Disculpe repetí el código de la función RT_NumerarParcialSQL()

Muy didácticas sus respuestas, pero me inclino por el script de PostgreSQL es muy práctico, algo que no tenía ni idea. Trataré de implementarlo si tengo dudas no dude que le escribo a su correo. Gracias Eduardo.

Respuesta
1

Visita:

Cursos de Excel y Macros

Por Dante Amor

----- --

Te paso la solución en excel con una macro.

Pon tus datos en las columnas A a la D, los resultados quedarán en las columnas F a la J.

Es importante que tus datos estén tal y como lo mostraste en tu imagen y como se muestran en la siguiente imagen:

La macro:

Sub Ordenar_Por_Sueldo()
'Por Dante Amor
  Dim dic As Object
  Dim i As Long, lr As Long, ini As Long, fin As Long
  Dim f As Range
  Dim ky As Variant
  '
  Application.ScreenUpdating = False
  '
  Set dic = CreateObject("Scripting.Dictionary")
  lr = Range("A" & Rows.Count).End(3).Row
  '
  Range("A:A"). Copy Range("F1")
  Range("B:B"). Copy Range("I1")
  Range("C:C"). Copy Range("G1")
  Range("D:D"). Copy Range("H1")
  '
  Range("F1:I" & lr).Sort Range("I1"), xlAscending, Header:=xlYes
  For i = 2 To lr
    dic(Range("I" & i).Value) = Empty
  Next
  '
  For Each ky In dic.keys
    ini = Range("I:I"). Find(ky,, xlValues, xlWhole, xlByRows, xlNext).Row
    fin = Range("I:I"). Find(ky,, xlValues, xlWhole, xlByRows, xlPrevious). Row
    With Range("F" & ini & ":I" & fin)
      .Sort Range("H" & ini), xlDescending, Header:=xlNo
      .Offset(, 4).Resize(, 1).Value = .Offset(1, 1).Resize(1).Value
    End With
  Next
  Application.ScreenUpdating = True
End Sub

----- --

https://www.youtube.com/watch?v=4klJVh_Ob0M&t=2s 

Sal u dos Dante Amor

Visita:

Cursos de Excel y Macros

Por Dante Amor

----- --

Si solamente quieres conocer el nombre del segundo, utiliza la siguiente fórmula matricial:

=INDICE($C$2:$C$15,MAX(SI($B$2:$B$15=F2,SI($D$2:$D$15=K.ESIMO.MAYOR(SI($B$2:$B$15=F2,$D$2:$D$15),2),FILA($C$2:$C$15)-FILA($C$2)+1))))

Si utilizas punto y coma:

=INDICE($C$2:$C$15;MAX(SI($B$2:$B$15=F2;SI($D$2:$D$15=K.ESIMO.MAYOR(SI($B$2:$B$15=F2;$D$2:$D$15);2);FILA($C$2:$C$15)-FILA($C$2)+1))))

Es una fórmula matricial, para aceptarla debes presionar al mismo tiempo las teclas:

Shift + Control + Enter

No solamente enter, notarás que la fórmula queda entre llaves { }

----- --

Tus datos en las columnas A a la D.

En la columna F debes poner los IDseccion únicos.

Pon la fórmula en la celda G2 y la copias hacia abajo.

----- --

RECOMENDACIONES:

https://www.youtube.com/watch?v=dy9w9zbkCaw&t=751s 

 https://www.youtube.com/watch?v=F_bZOUNVDiU&t=5s 

Sal u dos Dante Amor

Respuesta
1

Voy a responder exactamente a lo que dices. Si tengo una tabla Empleados como la tuya

Construyo una consulta como ( le he añadido un campo Orden para, valga la redundancia, ordenarlos dentro de cada Seccion)

El campo Orden es el que ves en la ventana de ZOOM

Cuando la abro

Me los ha ordenado por sección y dentro de ésta por sueldo.

Con esta consulta construyo otra

Le he añadido un campo Segundo como puedes ver en ZOOM, de forma que cuando

La abro

Que es la imagen que has puesto

Muchas gracias Julián, pero ahora necesito es como pregunta Eduardo y lo enseña Dante en Excel, es obtener únicamente los 3 registros.  Gracias de antemano.

En ese caso, con la tabla Empleados construyo un formulario y en el evento Al abrir le digo

Private Sub Form_Open(Cancel As Integer)
Me.RecordSource = "select idseccion,idempleado,empleado,sueldo from consulta1 where orden=2"
End Sub

De forma que cuando se abre muestra

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas