Rambler's Top100
Форум: MS ACCESSVBVBA MS OfficeMS SQL server
Новые сообщения: 0000

Форум: MS ACCESS

Вопросы связанные с MS ACCESS

Обновить визитку
Участники «Online»
Все участники

 
 

Доброго времени суток, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: повторы значений в поле....
 
 автор: osmor   (02.09.2009 в 15:32)   личное сообщение
 
 

3-й день кручу в голове никак не придумаю...
Попробую сформулировать вопрос, может решение придет.
есть набор значений (ну условно таблица) с полями
Val - тектовое 255
Org - Long
ID - Long
IDError - Integer (изначально равно 1 для всех записей)

Значения в поле VAL ОДНОЗНАЧНО повторяющиеся (именно по этому эти записи в набор и попали).

Задача для одинаковых VAL :
если есть запись с Org = 1 то
         если во ВСЕХ других записях с этим VAL поле ID равен текущему, то IDError для этих = 2,  а для текущей NULL
         если встречаются другие ID, то для каждого встречающегося ID, первая запись (фактически любая, но одна) IDError = 1, а все         остальные IDError = 2
если нез записи Org =1, то
         для всех одинаковых ORG
                      если во ВСЕХ других записях с этим VAL поле ID равен текущему, то IDError для этих = 2,  а для текущей NULL
                       если встречаются другие ID, то для каждого встречающегося ID, "первая" запись (фактически любая, но одна) IDError = 1, а все остальные IDError = 2

Попробую пояснить на примере
После обработки должно получиться:

VAL Org ID IDError
a    1    1    Null    (т.к. ORG = 1, а все остальные ID одинаковые
a    4    1    2
a    5    1    2
            
b    1    1    1     (т.к. ORG = 1, а ID попадаются разные, то в итоге должен проставить IDError = 1 
b    1    2    1      для одной записи в каждом ID, а в остальных IDError = 2)
b    2    1    2
b    2    1    2
b    3    5    1
            
c    2    1    NULL  (т.е. нет записей с ORG = 1, а для каждого org значение id одинаковое, то для "первого" idError = null
c    2    1    2            (для остальных idError = 2)
c    3    2    NULL
c    3    2    2
c    4    3    NULL
            
d    2    1    1    (Org <>1. для ORG есть разные ID, то  для каждого ORG и каждого ID, для "первой" записи IDError = 1, для остальных 
d    2    1    2     IDError = 2
d    2    2    1
d    2    3    1
d    2    3    2
d    3    1    NULL     (т.к. для ORG = 3 все ID одинаковые, то для "первой" записи IDError = Null для остальных IDError = 2
d    3    1    2
d    3    1    2
d    3    1    2

  Ответить  
 
 автор: osmor   (02.09.2009 в 15:46)   личное сообщение
35 Кб.
 
 

Вот пример данных

  Ответить  
 
 автор: Lukas   (02.09.2009 в 18:01)   личное сообщение
 
 

Может как то примерно так?
Качество кода и скорость пока не рассматриваем.

Удалено

Там где .Fields(3) = 1 можно не обновляться, но я для наглядности сначала обновил в таблице все на 0, а то не видно было, где я писал, а где так и было.
Добавлено: похоже орг упустил

  Ответить  
 
 автор: osmor   (02.09.2009 в 18:19)   личное сообщение
 
 

скорость тут вообще фигня вопрос, по оценкам это будет 2-3% от обрабатываемого кол-ва (т.е. 1000-1500 записей)
Кручу 2 идеи
1. Использовать SHAPE .. пока не до конца понял как можно приспособить
2. банальный Dcount или рекордсеты с условием
взял запись, проверил наличие Org =1, если есть, то проверил наличие разных ID, если есть взял записи для каждого ID ... ну и т.д.

Спасибо, код вечерком посмотрю

  Ответить  
 
 автор: Lukas   (02.09.2009 в 19:50)   личное сообщение
 
 

Этот вроде правильнее с точки зрения алгоритма:

Public Function UpdateErr()

    Dim oldVal As String
    Dim oldOrg As Long
    Dim oldID As Long
    Dim varBookmarkS As Variant
    Dim flgID As Boolean
    Dim strID As String
    
    With CurrentDb.OpenRecordset("SELECT Val, Org, ID, IDError FROM Исходная ORDER BY Val, Org, ID")
        Do Until .EOF
            flgID = True
            oldVal = .Fields(0)
            oldID = .Fields(2)
            If .Fields(1) = 1 Then
                varBookmarkS = .Bookmark
                Do While oldVal = .Fields(0) And flgID
                    flgID = flgID And oldID = .Fields(2)
                    .MoveNext
                    If .EOF Then Exit Do
                Loop
                .Bookmark = varBookmarkS
                If flgID Then
                    .Edit
                    .Fields(3) = Null
                    .Update
                    .MoveNext
                    Do While oldVal = .Fields(0)
                        .Edit
                        .Fields(3) = 2
                        .Update
                        .MoveNext
                        If .EOF Then Exit Do
                    Loop
                Else
                    oldID = .Fields(2)
                    strID = CStr(oldID) & ";"
                    .Edit
                    .Fields(3) = 1
                    .Update
                    .MoveNext
                    Do While oldVal = .Fields(0)
                        .Edit
                        If UBound(Filter(Split(strID, ";"), CStr(.Fields(2)), True)) > -1 Then
                            .Fields(3) = 2
                        Else
                            .Fields(3) = 1
                            oldID = .Fields(2)
                            strID = strID & CStr(oldID) & ";"
                        End If
                        .Update
                        .MoveNext
                        If .EOF Then Exit Do
                    Loop
                End If
            Else
                Do While oldVal = .Fields(0)
                    oldOrg = .Fields(1)
                    flgID = True
                    oldID = .Fields(2)
                    varBookmarkS = .Bookmark
                    Do While oldVal = .Fields(0) And oldOrg = .Fields(1) And flgID
                        flgID = flgID And oldID = .Fields(2)
                        .MoveNext
                        If .EOF Then Exit Do
                    Loop
                    .Bookmark = varBookmarkS
                    If flgID Then
                        .Edit
                        .Fields(3) = Null
                        .Update
                        .MoveNext
                        Do While oldVal = .Fields(0) And oldOrg = .Fields(1)
                            .Edit
                            .Fields(3) = 2
                            .Update
                            .MoveNext
                            If .EOF Then Exit Do
                        Loop
                    Else
                        oldID = .Fields(2)
                        .Edit
                        .Fields(3) = 1
                        .Update
                        .MoveNext
                        Do While oldVal = .Fields(0) And oldOrg = .Fields(1)
                            .Edit
                            If oldID = .Fields(2) Then
                                .Fields(3) = 2
                            Else
                                .Fields(3) = 1
                                oldID = .Fields(2)
                            End If
                            .Update
                            .MoveNext
                            If .EOF Then Exit Do
                        Loop
                    End If
                    If .EOF Then Exit Do
                Loop
            End If
        Loop
        .Close
    End With
End Function

  Ответить  
 
 автор: osmor   (03.09.2009 в 11:44)   личное сообщение
 
 

спасибо...
Вчера говорил в заказчиком
Выяснилось, что все не так.
что для разных диапазонов ID, VAL либо может быть повторяющиеся внутри для одного ID либо нет.
Если нет, то все просто один ID один VAL
Если можно, то тогда уникальность VAL определяется для совокупности ID и ORG
т.е. все решается добавлением таблицы с диапазонами и прописыванию для диапазона True или False
если False, то запроса на уникальность c группировкой по ID и VAL
если True , то запроса на уникальность c группировкой по ID, VAL и ORG
Потом просто в каждом повторяющемся наборе для "первой" записи IDERROR = NUll, а у остальных 2
Все решается несколькими запросами (возможно с созданием временной таблицы)
Так что извините что отнял время

Тема закрыта, вопрос снят.

Lukas - огромное спасибо идея с Bookmark - супер!!!

  Ответить  
 
 автор: Анатолий (Киев)   (03.09.2009 в 13:04)   личное сообщение
 
 

SELECT Исходная.Val, (SELECT Max(T1.Org) AS [Max-Org]
FROM Исходная AS T1
WHERE (((T1.Val)=Исходная.Val) AND ((T1.Org)=1))) AS IsOrg1, Исходная.Org, Min(Исходная.ID) AS MinID, Max(Исходная.ID) AS MaxID
FROM Исходная
GROUP BY Исходная.Val, Исходная.Org;

Этот запрос группирует по Val и Org, показывает Min ID и Masx ID, а также для каждого Val возвращает признак наличия Org=1 (IsOrg1 возвращакт 1 или Null). В каждой записи достаточно информации, чтоб после простой логики определить значение IDError и выполнить запрос на обновление записей.
Например для записи:

Val               IsOrg1  Org      MinID       MaxID
tir nbs lrrs               14     12000078    12000285

Org<>1 (14), нет записей с этим Val и Org=1 (IsOrg1=Null) и есть записи с разными индексами (12000078 <> 12000285), то в записях с этим Val, Org и ID = MinID (первая запись) меняем IDError на Null, а для ID <> MinID - на 2. Т.е. запрос типа:

UPDATE Исходная SET Исходная.IDError = IIf([Исходная]![ID]=12000078,Null,2)
WHERE (((Исходная.Val)='tir nbs lrrs') AND ((Исходная.Org)=14));

ИМХО, 926 операций обновления (столько возвращает запрос) быстрее, чем 1732 (записей в таблице).

  Ответить  
 
 автор: osmor   (03.09.2009 в 14:33)   личное сообщение
 
 

Сильно!
Снимаю шляпу!

  Ответить  
HiProg.com - Технологии программирования
Rambler's Top100 TopList