LINUX.ORG.RU

Как правильно выбрать данные (многие ко многим)?

 ,


0

1

Привет. Есть такая проблема. Есть, например, в одной базе данных (SQL) две таблицы - A и B. Там есть много полей... главное значение имеют A.id, B.id1, B.id2.

A.id - первичный ключ для таблицы A, есть B.id первичный для B, но он роли особой не играет, есть также два внешних ключа B.id1 и B.id2 (оба ссылаются на A.id)

Для конкретного A.id данные в таблице B могут как быть, так и нет, это надо учитывать.

То есть таблица B - своего рода хранит односторонние ссылки для отношения многие ко многим (B.id1 => B.id2)

Надо сделать выборку данных из таблицы A (не всю, а по условию WHERE), для вставки данных в другую базу, и параллельно делать выборки из B, где B.id1 = A.id. При этом учитывать, что записи в A, где A.id = B.id2 УЖЕ СУЩЕСТВУЮТ. То есть определить, в каком порядке выбирать/вставлять данные.

Для простоты предположим, что циклических связей (B.id1 => B.id2 и рядышком B.id2 => B.id1) нет, так как с ними задача нерешаемая, я так понял.

Собственно, как запрос строить? :( Возился с SQL, но так и не понял.

p.s. исходная база oracle, если играет какую-то роль.

UPDATE: я так понял, задача нерешаемая в той форме, в которой я озвучил, увы. Ок, буду думать по-другому.

я не очень понял задачу, но если сделать два left join-а A с B (один раз on A.id = B1.id1, второй - A.id = B2.id2) и потом отфильтровать те, в которых B2.id2 is not null получится не то что тебе нужно?

maloi ★★★★★ ()

в другую базу

не опечатка? какая связь между базами?

A.id = B.id2 УЖЕ СУЩЕСТВУЮТ

во второй базе? можно считать что в первой базе эти же связи и операций удаления не было?

параллельно делать выборки из B

по подробней пожалуйста

anonymous ()
Ответ на: комментарий от anonymous

Чуть поподробнее. сначала вторая база пустая. какая - не важно (пусть тот же sql, h2, например, или sqlite).

Сначала необходимо добавить все те строки A, на которые нет ссылок из B.id2=>A.id. Потом те, которые ссылаются на предыдущих. Потом те, которые ссылаются на них, и так далее.

Я строил такие запросы один за другим, но они получались большими. :)

Просто сходу вставить данные нельзя в произвольном порядке... так как B.id2 может ссылаться на ту запись в A, которая есть в старой базе, но ЕЩЁ НЕТ (не скопировали) в новую.

Если так непонятно, завтра попробую нарисовать. :(

BattleCoder ★★★★★ ()
Ответ на: комментарий от maloi

А я не очень-то понял, что вы ответили =) да и проблемы, чувствую, это не решает. Попробую на примере...

BattleCoder ★★★★★ ()

Итак. Пример.

A:

id, name,
1,'ivanov'
2,'petrov'
3,'sidorov'

B:

id,id1,id2
1,1,2

Означает, что 'ivanov' имеет ссылку на 'petrov', при этом 'sidorov' ссылок не имеет.

В этом случае я НЕ могу в новую (пустую) базу вставить строку 1 ('ivanov'), так как она имеет ссылку на несуществующий элемент(мне нужно ОДНОВРЕМЕННО выбирать строки из A и B, где A.id=B.id1)... мне надо сначала вставить 2 и 3 (в любом порядке), а потом только могу вставить 1.

Так понятнее?..

Вопрос в том, что строчек тысячи, и надо это как-то автоматически определять... это вообще возможно (или не факт)?

BattleCoder ★★★★★ ()
Последнее исправление: BattleCoder (всего исправлений: 1)

Копировать данные сначала из A, а потом только из B нехорошо тем, что они будут в какой-то промежуток времени не совсем правильными... недостоверными. Надо делать это транзакциями что ли. Либо есть данные, и они правильные, либо их нет.

А так если эту задачу нельзя решить, как я описал... именно так и придётся. Сам долго думал, оказалось сложным. :(

BattleCoder ★★★★★ ()

многие ко многим

две таблицы

/0

ЗЫ описание задачи ужасное, нифига не понятно, это если не считать, что отношение М2М состоит из трех таблиц.

Deleted ()

Либо я ничего не понял, либо здесь описано что угодно, только не отношение «многие ко многим». Причем описано непонятно, и пояснено в комментариях тоже непонятно. Впрочем, надо поспать.
ТС, напиши заодно, в какую структуру ты это все должен вставить.

thesis ★★★★★ ()

ТС, я сломал мозг пытаясь распарсить твою задачу. всем будет проще, если ты покажешь DDL таблиц и первые 10 строк в каждой.

val-amart ★★★★★ ()
Ответ на: комментарий от Deleted

ЗЫ описание задачи ужасное, нифига не понятно, это если не считать, что отношение М2М состоит из трех таблиц.

напряги фантазию и представь одну таблицу дважды

mashina ★★★★★ ()

Надо сделать выборку данных из таблицы A (не всю, а по условию WHERE), для вставки данных в другую базу, и параллельно делать выборки из B, где B.id1 = A.id. При этом учитывать, что записи в A, где A.id = B.id2 УЖЕ СУЩЕСТВУЮТ. То есть определить, в каком порядке выбирать/вставлять данные.

Что значат твои рассуждения про (существуют / не существуют) относительно новой таблицы в новой базе? Если ты хочешь перенумеровать id в новой базе для всех вновь вставленных значений, то на первом шаге вставляй в новую базу ВСЮ доступную информацию (например, добавив столбец old_id_a для хранения старых идентификаторов, либо временную таблицу соответствий (old_id_a, new_id_c)). А на втором шаге преобразуй вновь полученные строки со старых идентификаторов на новые, если нужно.

justAmoment ★★★★★ ()
Ответ на: комментарий от thesis

Ну одна сущность (A) имеет как бы ссылку на саму себя. Это очень даже «многие ко многим». Ссылки хранятся в таблице B.

Объясняю я и правда плохо. :( Слишком сложно, можно было проще. Наверное, зря я это ночью решил спросить.

BattleCoder ★★★★★ ()
Ответ на: комментарий от BattleCoder

Ну допустим я уже тоже проснулся и насчет нынешней структуры стало понятно. А целевая структура какой вид имеет?

thesis ★★★★★ ()
Последнее исправление: thesis (всего исправлений: 1)
Ответ на: комментарий от thesis

Целевая структура - nosql-хранилище, древовидное. Не хотел заострять на этом внимание... а то тут точно долго распинаться придётся. %)

Предположим для простоты, что просто сохранить в файл, в древовидном формате. Пусть тот же json:

[
{
"id": 1,
"name": "ivanov",
"b": [{"id2": 2}]
},
{
"id": 2,
"name": "petrov",
"b": []
},
{...},
...
]

Как-то так... примерно.

BattleCoder ★★★★★ ()
Последнее исправление: BattleCoder (всего исправлений: 1)
Ответ на: комментарий от BattleCoder

Ну сходу вот так:

select * from a;
+----+------------+
| id | name       |
+----+------------+
|  1 | ivanov     |
|  2 | petrov     |
|  3 | sidorov    |
|  4 | efimov     |
|  5 | rabinovich |
|  6 | smith      |
|  7 | obama      |
+----+------------+

select * from b;
+----+------+------+
| id | id1  | id2  |
+----+------+------+
|  1 |    1 |    2 |
|  2 |    2 |    4 |
|  3 |    4 |    7 |
|  4 |    6 |    7 |
|  5 |    7 |    1 |
|  6 |    1 |    7 |
+----+------+------+

select a.id, a.name, b.id2 from a left join b on a.id=b.id1 join a as aa on a.id=aa.id;
+----+------------+------+
| id | name       | id2  |
+----+------------+------+
|  1 | ivanov     |    2 |
|  2 | petrov     |    4 |
|  4 | efimov     |    7 |
|  6 | smith      |    7 |
|  7 | obama      |    1 |
|  1 | ivanov     |    7 |
|  3 | sidorov    | NULL |
|  5 | rabinovich | NULL |
+----+------------+------+

Оно? А как выбрать так, чтобы сразу вставить - не знаю :) Можно проверку целостности отключить, наверное, в смысле, объявить ключи после вставки данных.

thesis ★★★★★ ()
Последнее исправление: thesis (всего исправлений: 2)
Ответ на: комментарий от thesis

Ну в этом и был вопрос. :) Правда, left join лучше моего варианта наверное (я использовал подзапрос). А тут вопрос именно в том... строку petrov надо вставлять до строки ivanov, потому что она от неё зависит... вот в чём загвоздка.

Циклические связи вообще все ломают, но можно допустить, что их нет, или как-то убрать из исходной базы (так как это логическая ошибка, их быть не должно, они не несут смысла)

BattleCoder ★★★★★ ()
--create table A
--(
--    id   number   primary key,
--    name varchar2(20)
--);

--create table B
--(
--    id  number primary key,
--    id1 number,
--    id2 number
--);

--insert into A (id, name) values (1,'petrov');
--insert into A (id, name) values (2,'ivanov');
--insert into A (id, name) values (3,'sidorov');

--insert into B (id, id1, id2) values (1,1,2);
--insert into B (id, id1, id2) values (2,2,1);
--insert into B (id, id1, id2) values (3,1,3);

declare
 s_cond varchar2(50) := '%';
 i      number       := 0; --loop count 
 b      number       := 0; --loop count 
begin

 DBMS_OUTPUT.PUT_LINE('[');
 for rec1 in (select *
                from A
                where A.NAME like s_cond
             )
 loop
    
     if i = 0 then
     DBMS_OUTPUT.PUT_LINE('{');
     else
     DBMS_OUTPUT.PUT_LINE(',{');
     end if;
     DBMS_OUTPUT.PUT_LINE(' "id": '   || rec1.id   ||',');
     DBMS_OUTPUT.PUT_LINE(' "name": "'|| rec1.name ||'",');
     DBMS_OUTPUT.PUT(' "b": [');
     --цикл по таблице B -----------------
     b := 0;
     for rec2 in (select id2
                    from B
                   where B.ID1 = rec1.id
                 )
     loop
        if b = 0 then
         DBMS_OUTPUT.PUT('{');
        else
         DBMS_OUTPUT.PUT(',{');
        end if;
        DBMS_OUTPUT.PUT(' "id2": '   || rec2.id2 );
        DBMS_OUTPUT.PUT('}');
        b := b + 1;
        null;
     end loop;          
     -------------------------------------
     DBMS_OUTPUT.PUT(']');
     
     DBMS_OUTPUT.PUT_LINE('');
     DBMS_OUTPUT.PUT_LINE('}');
     i := i + 1;
 end loop;
 DBMS_OUTPUT.PUT_LINE(']');
end;

Как результат

[
{
 "id": 1,
 "name": "petrov",
 "b": [{ "id2": 2},{ "id2": 3}]
}
,{
 "id": 2,
 "name": "ivanov",
 "b": [{ "id2": 1}]
}
,{
 "id": 3,
 "name": "sidorov",
 "b": []
}
]
looper ()
Ответ на: комментарий от BattleCoder

Так если у тебя нереляционная БД, то не пофиг ли, каком порядке вставлять данные?

thesis ★★★★★ ()
Ответ на: комментарий от thesis

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

Понятно, что один из вариантов. Второй вариант - вставлять данные из B строго после вставки всего из A. В общем, я так и понял, что озвученная мною задача решения не имеет. Грустно.

BattleCoder ★★★★★ ()
Ответ на: комментарий от thesis

Там проверка целостности накручена сверху ;) Не хочу подробно объяснять.

BattleCoder ★★★★★ ()
Последнее исправление: BattleCoder (всего исправлений: 1)
Ответ на: комментарий от BattleCoder

При наличии циклических ссылок - не решается, конечно (таким простым образом). А они, как я понял, неизбежны. Ну да невелика беда же.

thesis ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.