Jump to content

ADO - Como comparar dois registos consecutivos de um recordset e apagar um deles


diogoarsousa
 Share

Recommended Posts

' Bom dia

' Tenho uma tabela chamada Caudais com com os seguintes campos = ID, Date e Caudal

' A tabela está ordenada por ID e Date

' Sei que existem registos duplicados, triplicados, etc. com o mesmo ID e Date

' Quero que o programa corra todos os registos da tabelam que compare cada um com o seguinte e apague o que tiver menor caudal.

' No entanto este programa nao está a funcionar convenientemente. Alguém me pode ajudar a corrigi-lo e a simplificá-lo? Obrigado



Dim Previous_ID As Integer

Dim Previous_Date As Integer

Dim Previous_Caudal as Integer

Dim Next_ID As Integer

Dim Next_Date As Integer

Dim Next_Caudal As Integer

Dim Sqlstring  as string


 

'Apago os registos importados duplicados na Base de Dados

Sqlstring = "SELECT * FROM Caudais WHERE Caudais.Date >= " & "20150101"

New ADODB.Recordset()

 
rst.Open(Sqlstring, "DSN=Diogo", ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockOptimistic, ADODB.CommandTypeEnum.adCmdText)

 
rst.MoveFirst()



[indent=1]
Do Until (rst.EOF)

Previous_ID = rst.Fields("ID").Value

Previous_Date = rst.Fields("Date").Value

Previous_Caudal = rst.Fields("Caudal").Value


rst.MoveNext()


If Not rst.EOF Then

Next_ID = rst.Fields("ID").Value

Next_Data = rst.Fields("Date").Value

Next_Caudal = rst.Fields("Caudal").Value


If Previous_ID = Next_ID And Previous_Date = Next_Date Then

If Previous_Caudal <= Next_Caudal Then

rst.Delete(ADODB.AffectEnum.adAffectCurrent)

rst.Requery()

Else

rst.MovePrevious()

rst.Delete(ADODB.AffectEnum.adAffectCurrent)

rst.Requery()

End If

End If

End If[/indent]

Loop
 

rst.Close()
rst = Nothing

Link to comment
Share on other sites

Olá CRLF,

Eu só pretendo verificar as datas superiores ou iguais a 20150101. E depois de o correr há muitos registos duplicados que não são apagados

Para simplificar a apresentação do problema eu retirei o campo Hora que agora acrescento.

A questão é que depois de criar o recorset, quando faço - rst.MoveFirst() - o programa salta logo para o registo em que a hora é 330

Agora o programa completo

Dim Previous_ID As Integer
Dim Previous_Hora As Integer
Dim Previous_Data As Integer
Dim Previous_Caudal as Integer

Dim Next_ID As Integer
Dim Next_Hora As Integer
Dim Next_Data As Integer
Dim Next_Caudal As Integer

Dim Sqlstring as string

 
'Apago os registos importados duplicados na Base de Dados

Sqlstring = "SELECT * FROM Caudais WHERE ZMC_Caudais.Data >= " & "20150101"
New ADODB.Recordset()
 
rst.Open(Sqlstring, "DSN=Diogo", ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockOptimistic, ADODB.CommandTypeEnum.adCmdText)
 
rst.MoveFirst()


Do Until (rst.EOF)

Previous_ID = rst.Fields("ID_ZMC").Value
Previous_Hora = rst.Fields("Hora").Value
Previous_Data = rst.Fields("Data").Value
Previous_Caudal = rst.Fields("Caudal").Value

rst.MoveNext()

If Not rst.EOF Then
Next_ID = rst.Fields("ID_ZMC").Value
Next_Hora = rst.Fields("Hora").Value
Next_Data = rst.Fields("Data").Value
Next_Caudal = rst.Fields("Caudal").Value

If Previous_ID = Next_ID And Previous_Hora = Next_Hora And Previous_Data = Next_Data Then
 If Previous_Caudal <= Next_Caudal Then
  rst.Delete(ADODB.AffectEnum.adAffectCurrent)
  rst.Requery()
 Else
  rst.MovePrevious()
  rst.Delete(ADODB.AffectEnum.adAffectCurrent)
  rst.Requery()
 End If
End If
End If

Loop
 
rst.Close()
rst = Nothing
 

ZMC_Caudais ID_ZMC Data Hora Caudal 101 20150101 15 0 101 20150101 30 1 101 20150101 45 5 101 20150101 100 5 101 20150101 115 2 101 20150101 130 1 101 20150101 145 5 101 20150101 200 9 101 20150101 215 10 101 20150101 230 2 101 20150101 245 14 101 20150101 300 6 101 20150101 315 0 101 20150101 330 0 101 20150101 345 7 101 20150101 400 0 101 20150101 415 0 101 20150101 430 0 101 20150101 445 0 101 20150101 500 0 101 20150101 515 1 101 20150101 530 2 101 20150101 545 0 101 20150101 600 6 101 20150101 615 0

Link to comment
Share on other sites

Muito obrigado passarito 👍

A ordenação da tabela por ID_ZMC, Data e Hora resolveu o problema de o programa saltar logo para o registo em que a hora é 330. Agora vai para o 1º registo. Mas causa-me estranheza porque ao olhar para a tabela, ela parecia (aparentemente) ordenada.

Quanto à outra questão, a de comparar dois registos consecutivos e apagar o de caudal menor, qual é a forma mais correcta de fazer?:

 


Do Until (rst.EOF)

Previous_ID = rst.Fields("ID_ZMC").Value
Previous_Hora = rst.Fields("Hora").Value
Previous_Data = rst.Fields("Data").Value
Previous_Caudal = rst.Fields("Caudal").Value

rst.MoveNext()

If Not rst.EOF Then

Next_ID = rst.Fields("ID_ZMC").Value
Next_Hora = rst.Fields("Hora").Value
Next_Data = rst.Fields("Data").Value
Next_Caudal = rst.Fields("Caudal").Value

If Previous_ID = Next_ID And Previous_Hora = Next_Hora And Previous_Data = Next_Data Then

If Previous_Caudal <= Next_Caudal Then

rst.Delete(ADODB.AffectEnum.adAffectCurrent)
rst.Requery()

Else

rst.MovePrevious()

rst.Delete(ADODB.AffectEnum.adAffectCurrent)
rst.Requery()

End If

End If

End If

Loop

 
rst.Close()
rst = Nothing


Edited by diogoarsousa
Link to comment
Share on other sites

Cada programador tem as suas próprias técnicas/hábitos de rotinas de programação.

Dito isto, é claro que não faria a rotina desta forma, no entanto parece-me que o problema aqui coloca-se quando o programa apaga um registo, independentemente de ser o anterior ou posterior, pois quando ele vai atribuir os valores do registo anterior não sei o que ele fará.

Para solucionar este problema colocaria o bloco onde é atribuído os valores do registo anterior em dois sitios:

- Imediatamente antes do inicio do ciclo "Do until" para garantir que entra no ciclo com esses valores

- No "else" do "if" de comparação dos valores anteriores e posteriores, pois quando apagas é porque os registos são iguais, se são iguais não vale a pena re-atribuir os valores do anterior

Por fim, quando se apaga o registo anterior, neste caso tem de se atribuir ao Previous_Caudal o valor do Next_Caudal

Só em nota de rodapé, há que ter em atenção se quando se lê um registo o ponteiro continua a apontar para esse registo ou para o seguinte, pois há programas que trabalham dessa forma. Se for o caso, para apagares o registo actual tens de andar uma vez para trás, se for o registo anterior terás de andar duas vezes para trás

Link to comment
Share on other sites

Para este tipo de operação não costumo usar o "DO". Uso o "While" e isso muda a forma de sequenciar o fluxo de informação.

Mas não vás refazer uma rotina toda por este motivo, além do mais não há uma forma melhor do que outra, antes aquela a que estamos mais habituados.

É uma abordagem diferente mas de igual modo válida e correcta.

Se essa já está quase a funcionar, implementa lá as alterações que te disse e diz qualquer coisa.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.