|
Вопрос # 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 потеряли "детей".
Надо что-то менять в консерватории. Отслеживать ссылочную целостность средствами приложение - плохое решение. Такие вещи нужно делать средствами СУБД.
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|