Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 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 Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: 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

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

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

UnHoly (статус: Посетитель), 22 июня 2011, 00:21 [#5]:

Вадим К: NOM уникален только для таблицы с 1500 записями, в большой таблице он может встречаться несколько раз.

Мережников Андрей: предложенный Вами запрос лишь объединит все данные в одном запросе, а нужно сделать выборку на совпадение.

в принципе наиболее подходящим нашел запрос: select NOM from t1,t2 where t1.NOM=t2.NOM

Теперь другая трудность. Нужно произвести замену найденных "NOM из большой таблицы" на "(назовем NEW_NOM) из маленькой". Одновременно с предыдущей процедурой это делать нельзя, т.к. после предыдущей процедуры пользователю должен быть показан лог с не найденными записями и тогда уж он будет решать заменять данные или нет. Такое уж тз дали=(
bugmenot

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

UnHoly (статус: Посетитель), 22 июня 2011, 09:09 [#8]:

Мережников Андрей: в мемо будут писаться те записи, для которых не нашлось совпадений в большой таблице
bugmenot

bugmenot (статус: 3-ий класс), 22 июня 2011, 10:04 [#9]:

Цитата (UnHoly):

для которых не нашлось совпадений

Тогда OUTER JOIN.

Цитата (Мережников Андрей):

вопросы надо задавать корректнее

Удваиваю.

В любом случае это делается запросом, а каким именно - будет ясно после озвучивания конкретного вопроса.
виконання програми розпочинається з того самого мiсця, де призупинилося.

UnHoly

UnHoly (статус: Посетитель), 22 июня 2011, 10:48 [#10]:

в целях исключения непонимания, добавил примечание к вопросу.
ArtGal

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

UnHoly (статус: Посетитель), 22 июня 2011, 12:34 [#12]:

ArtGal: спасибо. попробовал предложенный Вами запрос - комп ушел думать и не хочет возвращаться. Индексы добавить может?
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

ArtGal (статус: 1-ый класс), 24 июня 2011, 12:00 [#15]:

Как я понял t2 - родительская таблица с первичным ключем nom.
t2 - дочерняя таблица и поле t2.nom должно ссылаться на t1.nom.
Т.к. в БД не прописан CONSTRAINT, кто-то изменил поля nom и некоторые записи в t1 "осиротели", а в t2 потеряли "детей".
Надо что-то менять в консерватории. Отслеживать ссылочную целостность средствами приложение - плохое решение. Такие вещи нужно делать средствами СУБД.

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:49
Выполнено за 0.03 сек.