| 
| 
 | Вопрос # 5 431/ вопрос открыт / | 
 |  Приветствую, уважаемые эксперты!Ситуация:
 Есть 2 dbf-таблицы. 1-я на 150 тысяч строк, вторая на 1,5 тысячи. Задача заключается в том, чтобы найти совпадения по определенному полю (назовем его к примеру NOM). Иными словами берем Nom из первой строки второй таблицы и ищем строку с аналогичной записью во втророй. Находим - пропускаем, не находим - пишем в мемо. Переходим на следующую строку и тд.
 Вопрос:
 Как реализация данной процедуры будет наиболее оптимальна, с точки зрения скорости? SQL? Индексы? Если есть еще варианты, с радостью выслушаю.
 Примечание #1 (22 июня 2011, 10:45): таблица на 150 000 записей - t1таблица на 1500 записей - t2
 поле для сравнения - NOM. NOM уникален для t2. t2.Nom=t1.Nom может выстречаться в t1.NOM несколько раз, а может и не встретиться вовсе.
 поле для замены - NEW_NOM встречается только в t2.
 задача:
 1. создать запрос, в котором t2.NOM=t1.NOM;
 2. если t2.NOM НЕ(!!) ВСТРЕЧАЕТСЯ в t1.NOM, то t2.NOM пишется в Memo, для последующего вывода лога.
 3. исходя из результатов запроса t2.NOM=t1.NOM произвести замену t1.NOM на t2.NEW_NOM. Иными словами заменить данные в t1.dbf на t2.dbf по принципу t1.NOM:=t2.NEW_NOM
 
 
|  |   Вопрос задал: UnHoly (статус: Посетитель)Вопрос отправлен: 21 июня 2011, 14:53
 Состояние вопроса: открыт, ответов: 1.
 |  Ответ #1. Отвечает эксперт: ArtGal Здравствуйте, UnHoly!select t1.num from t1
 union
 selet t2.num from t2
 
|  | Ответ отправил: ArtGal (статус: 1-ый класс)Время отправки: 21 июня 2011, 17:19
 
 |  
 Мини-форум вопросаВсего сообщений: 15; последнее сообщение — 24 июня 2011, 12:00; участников в обсуждении: 5. 
|   | ArtGal (статус: 1-ый класс), 21 июня 2011, 17:18 [#1]:select t1.num from t1 union
 selet t2.num from t2
 |  
|   | Вадим К (статус: Академик), 21 июня 2011, 18:08 [#2]:Если о NOM что то известно (например, это числа с известного диапазона), то можно очень хорошо оптимизировать алгоритм. NOM в пределах одной таблицы уникальный?
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Мережников Андрей (статус: Абитуриент), 21 июня 2011, 19:39 [#3]: Цитата (ArtGal): select t1.num from t1 union selet t2.num from t2  union вернет множество всех строк, возвращенных обоими запросами за исключением дубликатов - поучите SQL еще.
 Если надо выбрать только строки запроса из первой таблицы (t1), для которых нет соответствия во второй таблице (t2), то надо использовать except, а не union следующим образом:
 select t1.nom from t1
 except
 select t2.nom from t2.
 Да, автор, уточните вот это:
 
 Цитата (UnHoly): берем Nom из первой строки второй таблицы и ищем строку с аналогичной записью во втророй что с чем сравниваем?
 |  
|   | ArtGal (статус: 1-ый класс), 21 июня 2011, 23:04 [#4]:> Есть 2 dbf-таблицы. ... > берем Nom из первой строки ВТОРОЙ таблицы
 > и ищем строку с аналогичной записью во ВТОРОЙ.
 > Находим - пропускаем, не находим - пишем в мемо.
 
 А причем здесь ПЕРВАЯ таблица?
 
 Если надо выбрать записи первой таблицы, для которых нет соответствия во второй таблице, то:
 select t1.nom
 from t1
 where not(exist(select t2.nom
 from t2
 where (t1.nom = t2.nom)))
 Очевидно, индексы по поля Nom в обеих таблицах будут полезны.
 |  
|   | UnHoly (статус: Посетитель), 22 июня 2011, 00:21 [#5]:Вадим К: NOM уникален только для таблицы с 1500 записями, в большой таблице он может встречаться несколько раз. 
 Мережников Андрей: предложенный Вами запрос лишь объединит все данные в одном запросе, а нужно сделать выборку на совпадение.
 
 в принципе наиболее подходящим нашел запрос: select NOM from t1,t2 where t1.NOM=t2.NOM
 
 Теперь другая трудность. Нужно произвести замену найденных "NOM из большой таблицы" на "(назовем NEW_NOM) из маленькой". Одновременно с предыдущей процедурой это делать нельзя, т.к. после предыдущей процедуры пользователю должен быть показан лог с не найденными записями и тогда уж он будет решать заменять данные или нет. Такое уж тз дали=(
 |  
|   | bugmenot (статус: 3-ий класс), 22 июня 2011, 04:03 [#6]:UNION? тут скорее INNER JOIN виконання програми розпочинається з того самого мiсця, де призупинилося.
 
 |  
|   | Мережников Андрей (статус: Абитуриент), 22 июня 2011, 06:30 [#7]: Цитата (bugmenot): предложенный Вами запрос лишь объединит все данные в одном запросе, а нужно сделать выборку на совпадение вопросы надо задавать корректнее. EXCEPT оставляет только те записи из первой таблицы, для которых нет соответствия во второй, а не объединяет результаты запросов
 Цитата (UnHoly): в принципе наиболее подходящим нашел запрос: select NOM from t1,t2 where t1.NOM=t2.NOM как это согласуется с фразой:
 Цитата (UnHoly): Находим - пропускаем, не находим - пишем в мемо. Что здесь будет писаться в memo?
 |  
|   | UnHoly (статус: Посетитель), 22 июня 2011, 09:09 [#8]:Мережников Андрей: в мемо будут писаться те записи, для которых не нашлось совпадений в большой таблице |  
|   | bugmenot (статус: 3-ий класс), 22 июня 2011, 10:04 [#9]: Цитата (UnHoly):  для которых не нашлось совпадений Тогда OUTER JOIN.
 
 Цитата (Мережников Андрей): вопросы надо задавать корректнее Удваиваю.
 
 В любом случае это делается запросом, а каким именно - будет ясно после озвучивания конкретного вопроса.
 виконання програми розпочинається з того самого мiсця, де призупинилося.
 
 |  
|   | UnHoly (статус: Посетитель), 22 июня 2011, 10:48 [#10]:в целях исключения непонимания, добавил примечание к вопросу. |  
|   | ArtGal (статус: 1-ый класс), 22 июня 2011, 12:14 [#11]:> 1. создать запрос, в котором t2.NOM=t1.NOM; Не надо.
 
 > 2. если t2.NOM НЕ(!!) ВСТРЕЧАЕТСЯ в t1.NOM,
 > то t2.NOM пишется в Memo,
 > для последующего вывода лога.
 select t2.nom
 from t2
 where not(exist(select t1.nom
 from t1
 where (t1.nom = t2.nom)))
 Результат пишем в требуемое место.
 
 > 3. исходя из результатов запроса t2.NOM=t1.NOM
 > произвести замену t1.NOM на t2.NEW_NOM.
 > Иными словами заменить данные в t1.dbf
 > на t2.dbf по принципу t1.NOM:=t2.NEW_NOM
 Не уверен, что это прокатит для dbf, но смысл будет понятен.
 for
 select t1.nom, t2.nom_new
 from t1, t2
 where t1.nom = t2.nom
 into :nom, :nom_new -- надо заранее объявить переменные
 do
 update t1
 set t1.nom = :nom_new
 Если подумать, то можно все свести в один update t1.
 Что-то типа такого:
 update t1
 set t1.nom = (select t2.nom_new
 from t1, t2
 where t1.nom = t2.nom)
 |  
|   | UnHoly (статус: Посетитель), 22 июня 2011, 12:34 [#12]:ArtGal: спасибо. попробовал предложенный Вами запрос - комп ушел думать и не хочет возвращаться. Индексы добавить может? |  
|   | ArtGal (статус: 1-ый класс), 22 июня 2011, 12:44 [#13]:КОНЕЧНО! По полям nom в обоих таблицах.
 |  
|   | Мережников Андрей (статус: Абитуриент), 22 июня 2011, 17:11 [#14]:попробуйте вот так: select t2.nom from t2
 except
 select t1.nom from t1.
 Этот запрос должен вернуть t2.nom, которых нет в t1
 |  
|   | ArtGal (статус: 1-ый класс), 24 июня 2011, 12:00 [#15]:Как я понял t2 - родительская таблица с первичным ключем nom. t2 - дочерняя таблица и поле t2.nom должно ссылаться на t1.nom.
 Т.к. в БД не прописан CONSTRAINT, кто-то изменил поля nom и некоторые записи в t1 "осиротели", а в t2 потеряли "детей".
 Надо что-то менять в консерватории. Отслеживать ссылочную целостность средствами приложение - плохое решение. Такие вещи нужно делать средствами СУБД.
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |