Подскажите с запросом.. Это реально???

Работа VB и СУБД (Access, MSSQL, MySQL, Oracle и пр.)
Правила форума
При создании новой темы не забывайте указывать используемую СУБД.
iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Подскажите с запросом.. Это реально???

Сообщение iGrok » 13.09.2007 (Чт) 22:17

Значить так. Есть три таблицы:
Grp: (Grp_ID,Parent_ID,Grp_Name,...)
Tov: (T_Art,Grp_ID,...)
Main: (ART,NAME...)

(Указал только то, что нужно для понимания задачи, ессесно)

По таблице Grp строится дерево групп товара.
В таблице Tov - соответствия товара товарным группам.
Таблица Main - актуальность товара. То есть реально есть только те артикулы, которые есть в этой таблице.

Задача - запросом отфильтровать лишние ветви дерева.
Лишние - это те, в которые не входит ни один артикул, и у которых при этом нету потомков.

Первая попытка была делать это перебором, но 3000 групп и 28000 артикулов - это 5 минут на моей машинке,
а на рабочих - все 15.

В итоге я, не очень хорошо зная SQL за пару часов родил вот это:
Код: Выделить всё

SELECT DISTINCT G.*
FROM (Grp G INNER JOIN Tov T ON T.Grp_ID = G.Grp_ID) INNER JOIN Main M ON M.ART=T.T_Art
ORDER BY G.Grp_Name
UNION
SELECT DISTINCT G.*
FROM Grp G INNER JOIN Grp G1 ON G.Grp_ID=G1.Parent_ID
ORDER BY G.Grp_Name


И все бы замечательно, но после этого я понял, что условия усложняются. ((
Первое условие - отфильтровать те группы, в которые не входит ни один артикул сохраняется,
А вот второе - у группы не должно быть также "пустых" потомков.
Иначе те группы, которые до фильтрации имели только пустых потомков, после фильтрации сами становятся "пустыми".

Соответственно вот это:
Код: Выделить всё

SELECT DISTINCT G.*
FROM (Grp G INNER JOIN Tov T ON T.Grp_ID = G.Grp_ID) INNER JOIN Main M ON M.ART=T.T_Art
ORDER BY G.Grp_Name

сохраняется.

А вот вторая часть:
Код: Выделить всё

SELECT DISTINCT G.*
FROM Grp G INNER JOIN Grp G1 ON G.Grp_ID=G1.Parent_ID
ORDER BY G.Grp_Name

Нуждается в переделке. Нужно, чтобы выбирались только те группы, которые имеют "непустых" потомков..

Хелп плиз. Моск уже кипит (((
label:
cli
jmp label

VVitafresh
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1641
Зарегистрирован: 12.05.2005 (Чт) 14:44
Откуда: Херсон, UA

Сообщение VVitafresh » 13.09.2007 (Чт) 23:53

Кинул бы тестовый mdb файлик для наглядности что ли...
Никакую проблему невозможно решить на том же уровне, на каком она возникла. Нужно стать выше этой проблемы, поднявшись на следующий уровень.

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Сообщение iGrok » 14.09.2007 (Пт) 0:50

Хм тестовый mdb.. ))
Там коммерческая база на 30к артикулов и еще дерево на 3к веток..
Их кинуть не могу ))

Тестовик вроде наваял за полчасика.. Там и запрос этот сразу прописан.
Фишка - "Группа 5.16" не имеет в себе ни одного арикула. Только 2 пустые ветки. После фильтрации 2 ветки пропадают, а она, зараза, остается(что вполне логично, в свете того, какой запрос написан) и тоже становится пустой. Вот.
У вас нет доступа для просмотра вложений в этом сообщении.
label:
cli
jmp label

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 14.09.2007 (Пт) 21:40

Циклически, выбирать и выбирать раз за разом, каждый раз используя предыдущие результаты как основу для поиска новых.
Одним запросом не получится.
Скорее всего получится на SQL Server 2005 с его with, но это не к тебе.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Сообщение iGrok » 14.09.2007 (Пт) 22:35

GSerg писал(а):...каждый раз используя предыдущие результаты как основу для поиска новых...
Можно чутка подробнее в этом месте? Хотя бы направление поиска.
Если я правильно тебя понял, мне придется каждый раз просматривать результаты запроса в рекордсете, модифицировать запрос "по обстановке", и еще раз его выполнять. Или ты имел в виду что-то другое?
Я не совсем понимаю, как через Jet.OLEDB.4.0 сделать запрос, используя результат запроса, как таблицу для нового запроса. (во загнул-то..)
Хм. Кажется, игра не стоит свеч..

Кстати, если я еще не совсем выжил из ума, кажется я таки знаю, как при фиксированном/известном кол-ве уровней вложенности сконструировать запрос, который будет выдавать мне нужный список..

Что-то типа нескольких UNION'ов, которые будут мне выдавать список групп, имеющих "непустых" потомков нужного уровня...

Если думать в этом направлении, можно попробовать сначала узнать максимальный уровень вложенности... Но это тоже можно сделать только тупым перебором дерева, или нет?

Или я вообще думаю не в том направлении, и стоит перестать забивать голову всякой фигней? ,-)
label:
cli
jmp label

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 15.09.2007 (Сб) 1:54

Попробуй как в приложенном файле - там 4-ре запросика и код в модуле. К сожалению данных в табличках мало чтобы на скорость как следует проверить - придется тебе...

P.S На MS SQL было бы проще...
У вас нет доступа для просмотра вложений в этом сообщении.
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Сообщение iGrok » 15.09.2007 (Сб) 12:14

Спс.. Поковыряю..

Один трабл. Я НЕ МОГУ ничего добавлять в базу.

Прямо сейчас проверить не могу..
Я правильно понимаю, что вот это:
Код: Выделить всё

SELECT *
FROM Grp
WHERE Grp_ID IN(SELECT Parent_ID FROM GrpQ1);

Можно представить, как:
Код: Выделить всё

SELECT *
FROM Grp
WHERE Grp_ID IN(SELECT Parent_ID FROM (SELECT ... FROM ... ));

То есть вместо GrpQ1 подставить текст самого запроса GrpQ1?
label:
cli
jmp label

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 15.09.2007 (Сб) 13:03

iGrok писал(а):Один трабл. Я НЕ МОГУ ничего добавлять в базу.


В коде нет никакого добавления в базу. Смотри внимательней.

iGrok писал(а):Я правильно понимаю, что вот это:
Код: Выделить всё
SELECT *
FROM Grp
WHERE Grp_ID IN(SELECT Parent_ID FROM GrpQ1);

Можно представить, как:
Код: Выделить всё
SELECT *
FROM Grp
WHERE Grp_ID IN(SELECT Parent_ID FROM (SELECT ... FROM ... ));

То есть вместо GrpQ1 подставить текст самого запроса GrpQ1?


Можно, но в Access-e этим все одно ничего не выиграешь. А так удобней и проще для понимания.

И объединение GrpQx через UNION (что в принципе и хотелось бы сделать) приведет лишь к диким тормозам. Поэтому они объединяются через код...
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 15.09.2007 (Сб) 13:27

А вот вариантик не использующий запросов из базы - все из кода:

Код: Выделить всё
Public Sub t()
    Const sSQL1 As String = "SELECT * FROM Grp WHERE Grp.[Grp_ID] In (SELECT DISTINCT Grp_ID FROM Tov T INNER JOIN Main M ON T.T_Art LIKE M.ART)"
    Const sSQL2 As String = "SELECT * FROM Grp WHERE Grp_ID IN(SELECT Parent_ID FROM (|))"
    Const sf As String = "Grp_ID="
   
    Dim cn As New ADODB.Connection
    Dim rg As New ADODB.Recordset, r As ADODB.Recordset, f As ADODB.Field
    Dim i As Integer, sSQL As String
   
    cn.CursorLocation = adUseClient
    cn.ConnectionString = CurrentProject.Connection.ConnectionString
    cn.Open
   
    sSQL = sSQL1
    Set rg = New ADODB.Recordset
    rg.Open sSQL, cn, adOpenStatic, adLockOptimistic
    Set rg.ActiveConnection = Nothing
    rg!Grp_ID.Properties!Optimize = True
   
    If Not rg.EOF Then
        For i = 0 To 10
            sSQL = Replace(sSQL2, "|", sSQL)
            Set r = New ADODB.Recordset
            r.Open sSQL, cn, adOpenStatic, adLockOptimistic
            If r.EOF Then Exit For
            Do Until r.EOF
                rg.Find sf & r!Grp_ID, , , 1
                If rg.EOF Then
                    rg.AddNew
                    For Each f In rg.Fields
                        f = r(f.Name)
                    Next f
                    rg.Update
                End If
                r.MoveNext
            Loop
        Next i
    End If
    rg.Sort = "Grp_ID"
   
    Debug.Print
    Debug.Print "RecordCount = "; rg.RecordCount
    Do Until rg.EOF
        Debug.Print rg!Grp_ID, rg!Parent_ID, rg!Grp_Name, rg!AnyFields
        rg.MoveNext
    Loop
End Sub
Код: Выделить всё
Последний раз редактировалось Andrey Fedorov 15.09.2007 (Сб) 13:48, всего редактировалось 1 раз.
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Сообщение iGrok » 15.09.2007 (Сб) 13:37

Угу.. Спасибо. Буду тестировать и разбираться.

UPD:
Код: Выделить всё
INNER JOIN Main M ON T.T_Art LIKE M.ART

Почему "LIKE", а не "="
Длина полей одинакова. Совпадния мне нужны только строгие. LIKE работает быстрее?

UPD2:
С LIKE комп подвис на полчаса. С "=" все достаточно быстро - 2-3 сек. Но я как-то не заметил эффекта при фильтрации. То есть он мне выводит даже больше групп, чем при моем запросе. Естественно, пустые есть.
Ковыряю дальше, спасибо за направление поиска.
label:
cli
jmp label

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 16.09.2007 (Вс) 22:01

iGrok писал(а):Почему "LIKE", а не "="
Длина полей одинакова. Совпадния мне нужны только строгие. LIKE работает быстрее?


Ну поставь "="
Просто у тебя это поле почему-то текстовое, хотя в нем числа...

iGrok писал(а):То есть он мне выводит даже больше групп, чем при моем запросе. Естественно, пустые есть.


По идее там пустых быть не должно. Я в твоей тестовой базе их не обнаружил...
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Сообщение iGrok » 17.09.2007 (Пн) 0:31

Ну текстовое оно потому что "тут так заведено".. Оно уже лет 7 как текстовое.. Изменить это я не могу. ))
Впрочем, кажись в этом году будем перелезать на 1С.. Вот гемора-то будет... ))))

Угу. Я тоже. А вот на полной - есть.. Ладно, попробую побороть все это дело уже сам. Пасиба за пинок в нужном направлении, и за помощь.
label:
cli
jmp label


Вернуться в Базы данных

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 223

    TopList  
cron