Все ленты — последние статьи

Репликация, синхронизация из двух баз например на Firebird , гетерогенные запросы . Сравнение таблиц

Статья от автора Крайнего http://krayny.ru:   Вопрос очень интересный, но наверно готовые программы не подойдут по синхронизации баз.  Есть три базы: А(таблица 1,2,3)- расположение в интернет на дохлых скоростях, доступ всеми юзерами и базы В(таблица1,2) и С(таблица3) которые дополняют базу А из других источников. Вся проблема в таблицах поля ID — уникальным записям. которые могут не совпадать при добавлении в базу А с другими базами В, С. Предварительно вижу решение, создания дополнительной таблицы в базе А, с ходом и логом синхронизации на котором будут ID всех баз источник и получатель, дата обновления, имя таблицы первоисточника. Второй вариант создание в базе А, в каждой таблице доп. поля с ID номером соотвествия из другой базы (например В). С новыми записями понятно, а вот актуальностью самих записей которые редактировались, думаю тут только решение — отдельные поля по датам обновления, либо что-то то похожее на контрольную сумму всей строки чтоб засекать измения.  Делать несколько этапную синхронизацию. как практически реализую думаю. Профессорских статей в интернет много, но кратких и практических мало, нужно смотреть как это будет работать у самого )).

Зеркалирование, полный клон не подходит т.к. будут отличатся ID в разных базах с одинаковыми записями. И на базе А возможно подтирание старой информации. Начал движение в сторону работы с каждой таблицей базы, а именно по вопросу сравнение таблиц. Тут решено дополнять базы на информацию которой нет в базе А, в этом варианте тогда должно быть уникальное еще поле помимо ID записи. У меня оно нашлось, спец. № отличительный по ней и будет сравнивать, у кого то может быть эл. почта, счет — фактура, № заказа , артикул и т.п.

 Мы имеем одну прогу, с соединенными базами, допустим двумя с разных IP. И тут наткунулся на проблему. Из Delphi не могу сделать запрос сравнивания двух таблиц из разных БД. Отписался на форумы, ответ был унылый, не возможно или сложными путями, а хотел делать уже на найденных примерах. Вот вопрос на форуме.

Есть две разные базы(соединение в одной программе, на разные IP) через компоненты FIB(FIBDatabase) реализация на Delphi. Нужно сравнить две таблицы по полям одинаковые по структуре. Пытаюсь сделать что-то вроде этого;
ПРИМЕР
select x1.fld from table x1 where not EXISTS(select x2.fld from table x2 where x2.fld=x1.fld) — выбрать записи которые не совпадают.

но с pfibdataset не могу указать вторую таблицу в другой базе, названия таблиц совпадают.
и не могу продолжить
DM.efSDS.SelectSQL.Clear;
DM.efSDS.SelectSQL.Add('SELECT X1.fld FROM X1 WHERE....');

На форуме видел и это ПРИМЕР: SELECT a.fld1, a.fld2 FROM db1.table1 a, db2.table1 b WHERE a.id=b.id, и это не мойму как сделать.

Ясно все когда две таблицы в одной базе. Как мне в коде запроса сослатся на другую таблицу в другой базе( подключенные в разных FIBDatabase,fibdataset ) с таким же именем, не могу понять как практически реализовать это. И вывести как угодно , допустим DBGrid. Может кто подскажет как на Delphi это реализовать, примеры.

В основном получил два ответа: 1. Как-то через BDE 2. Что это гетерогенные запрос , п..дец даже не представляю что это, в Firebird не применимый (кто-то пишет, можеть быть возможно в Firebird 3.0). Были ответы перехода на платные базы и возможности делать гетерогенные запросы в Oracle. Тут стало, ясно, натнулся на камни, все не просто.

Был ответ, делать два разных запроса по каждой таблице и сравнивать их, почти построчно.Логически выглядит примерно так наверно

while not IBQuery1.Eof do
begin
IBTable2.Insert;
for i:=0 to IBQuery1.FieldCount-1 do
IBTable2.Fields[i].Value:=IBQuery1.Fields[i].Value;
IBTable2.Post;
IBQuery1.Next;
end;

Мда, с 100 записями все просто было, а база большая. Кажется, тупик. И мысли поворачиваются назад к идеи в начале статьи, отдельная таблица сравнения или доп. поле. Все эти сложные замуты и поиска готового варианта или комманд запроса, какие то переборы записей и т.п. — все не подходит. И тут Интернет НЕ ПОМОГ !.  Будет  делатся по совственному принципу, думаю получится быстро. 

Личное решение, которое пойдет не только к Firebird:

 1. У всех баз есть свои записи с ID, надо следить когда были измения, неважно какие и что в строках. Измения будет следить отдельным полем Даты+время, создаем во всех таблицах и на всех базах допустим поле data_edit (новая запись БД , дату ставим текущую, редактирование тоже). Зачем всем базам? При копирование записей в базу А(основную) , например с В(источники) тоже переносим время. Когда даты не совпадут, станет ясно база менялась у кого-то.

 2. Для быстрого переноса на базу А(основную), должно быть место куда мы записываем какое последнюю последовательную ID с баз B,C мы переносили. Со временем данные новые появляют на базах B,С, ID увеличиваются. Уточняем какие последние сейчас на B,С, на чем остановились на А , и докопируем новые данные. Остается проблема как распознавать разные базы B, С, кто есть кто — это не проблема, просто, создадим отличительные где-то метки в базе. 

3. Получается для обслуживания поле data_edit, фиксация последнего ID при переносе с других баз B, C. Для надежности и ясности добавляем в базу А еще два поля во все таблицы это ID первоисточника из других баз(допустим ID_primary) и поле метки с какой  базы дополнения (base_primary) ,

4. Остается актуализация базы А, когда нет новых записей, но наличием редактирования. Тут нам уже помогут поле data_edit что мы создали и его быстрое нахождение в другой базе по полю ID_primary, а base_primary — укажет мы ли тут хозяйничали.  Имея даты изменения, можно быстрее следить только за изменнными данными, а не гонять все базы от 1 записи и до бесконечности....

Решение покажется сложным, но логически очень быстрым при дохлом интернет у базы А. Остается реализовать это.

5. Создаем програмулку или кнопочку, которая сама собирает названия таблиц, раставляет новые метки, создает новые поля в оговоренные в пунктах 1-4 выше, не ковыряя все руками (в разработке).

6. В разработке....

 

 

 

Наброски.

INSERT INTO CURRENCY (ID, ISO_LAT, NAME, ISSHOW, HTMLCODE, RCODE) VALUES (840, 'USD', 'Доллары США', 'Y', '$', 'R01235');
INSERT INTO CURRENCY (ID, ISO_LAT, NAME, ISSHOW, HTMLCODE, RCODE) VALUES (810, 'RUR', 'Рубли РФ', 'Y', 'р.', NULL);

 MS SQL Server + FireBird = Дружба http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1412

 

Из форума сравнение и замена MINUS

 

I have two equal queries whit different filter applied on the same table. the first query returns (1,2,3,4,5) and the second returns (3,4,5).

I want apply the MINUS/EXCEPT operator: select1 minus select2 = (1,2)

How should I implements this logic using firebird SQL dialect ? (I'musing superserver v2.1)

I'm getting the opposite results performing select1 UNION select2 = (1,2,3,4,5)

thanks

 

Ответы

In FB there is no minus operator, so :

select x1.fld fromtable x1
wherenotEXISTS(select x2.fld fromtable x2 where x2.fld=x1.fld)

The MINUS operator does not exist in Firebird. The closest approximation I can think of is something like the example below. This uses Common Table Expressions, introduced in Firebird 2.1, but could of course also work with subqueries (I just find CTE more readable)

WITH select1 AS(
SELECT id,....),
select2 AS(
SELECT id,....)SELECTFROM select1
LEFTJOIN select2 ON select2.id = select1.id -- more conditions…?WHERE select2.id ISNULL

 

In this query I use LEFT JOIN to combine select1 and select2, and then only retain those rows from select1 that do not occur in select2

 

Из форума.

Нужно объединить запросы. Например, есть запрос суммарные покупки за день, есть запрос суммарные продажи за день. Нужно чтобы в результирующем наборе были поля: дата, объем покупок, объем продаж. Как это сделать? К сожалению в Interbase нет конструкции типа
select * from table1 left join (select * from table2).

Ответы:

1. select (select count(*) from table1), (select count(*) from table2) from rdb$database

2.

Можно использовать UNION если поля результирующих рекордсетов одинаковые

например

select дата, объем, 1 as is_sell
from [таблица продаж]
union
select дата, объем, 0 as is_sell
from [таблица покупок]

 

 из форумов…

Возможно я не верно понял Ваш вопрос, но что если попробовать так:

SELECT * FROM Table1 T1, Table1 T2, Table2 TT WHERE
TT.id_postavshik = T1.id and TT.id_poluchatel = T2.id

Если что не так то объясните подробнее что Вам требуется …

 

 хлам сравнения…

SELECT T1.ID, T2.ID
FROM T1
FULL OUTER JOIN T2 ON (T2.ID = T1.ID)
WHERE T1.ID IS NULL OR T2.ID IS NULL

 

типа этого
select t1.*
from table1 t1 left join table2 t2 on t1.id = t2.id
where t2.id is null

select .....from table1 where not exists(select…from table2 where…)
Пойдет ?

 

Данный вопрос не закрытый, редактируется по мере реализации вопроса…