Копирование строк из Грида в таблицу БД из двух связанных таблиц
Есть две связанные по ключу таблицы (Таблица 1 и 2), которые вывожу в 2 Грида.
Связь между таблицами - один ко многим. (База - SQL Server 2000).
Например, в таблице 1 поля такие:
GostID - текстовое поле и т.д.
В таблице 2:
CardID - int
Lnos - float и т.д.
Понятно, что ключ связи CardID.
Компоненты загрузки таблиц - ADOQuery.
И есть 2 таблицы (3-я и 4-я), полностью аналогичны по полям исходным. В них копируются
выделенные в Гриде строки.
Нужно:
выделить строки в Гриде 1 (из таблицы 1) и скопировать их в 3 таблицу . Но при этом каким-то образом из таблицы 2 тоже копировать строки, связанные по ключу с табл. 1, в таблицу 4. Чтобы связь эта в новых таблицах была сохранена.
Понимаю, что как-то нужно использовать закладку для табл. 2, но как узнать коды новых ключей, ведь они станут известны только после вставки строк из 1 таблицы?
Еще отмечу, что в данном примере в 3-й и 4-й таблицах поля CardID и BreakID обязательно должны быть полями идентефикации (счетчиками). Поэтому при вставке строк из первой таблицы нельзя предугадать, какие коды CardID получат строки, вставленные в таблицу 3.
Если нужно, могу выложить пример по выполнению 1-й задачи, где копирование происходит из 1 таблицы (без связанной 2-й).
Теоретически для этого достаточно, после команды типа
INSERT INTO table3(gostid) VALUES("...")
дать запрос
SELECT SCOPE_IDENTITY()
и после этого вставить записи из 2й таблицы
INSERT INTO table4 (cardid, lnos, ...)
SELECT :new_cardid, lnos, ...
FROM table2 WHERE cardid=: old_cardid
TDataSet* gtkn = Grid_Volume->DataSource->DataSet;
AnsiString sql_tkn = "";
gtkn->DisableControls();
int crno = gtkn->RecNo;
try
{
for(SET::iterator it=bookmarks.begin();it!=bookmarks.end();it++)
{
gtkn->RecNo = *it;
sql_tkn += gtkn->FieldByName("CardID")->AsString + ",";
}
sql_tkn.SetLength(sql_tkn.Length()-1);
// Алгоритм копирования
AnsiString SectorTable = "Loading_Card_Sector"; //Откуда копировать
AnsiString CardTable = "Loading_Card_21030"; //Куда копировать
AnsiString SectorBreak = "Loading_Break_Sector"; //Откуда копировать
AnsiString CardBreak = "Loading_Break_21030"; //Куда копировать
TADOCommand *cmtkn = ADOCommand1;
cmtkn->ParamCheck = true;
cmtkn->Prepared = false;
cmtkn->CommandText = AnsiString("") +"\
Insert Into " + CardTable +" (KodSyst, GostID, NameRD) \n\
Select KodSyst, GostID, NameRD \n\
From " + SectorTable + " \n\
Where CardID in (" + sql_tkn + ") \n\
insert into "+ CardBreak +" (CardID, Sp20i19) \n\
Select tp2.CardID, tc1.Sp20i19 \n\
From "+ SectorBreak +" tc1 \n\
inner join "+ SectorTable + " tp1 on tc1.CardID = tp1.CardID \n\
inner join "+ CardTable + " tp2 on tp2.KodSyst = tp1.KodSyst \n\
Where tp1.CardID in (" + sql_tkn + ") \n\
";
cmtkn->Execute();
}
__finally
{
gtkn->RecNo = crno;
gtkn->EnableControls();
}
[/COLOR]
Ошибка такая:
Вопрос такой: почему в Билдере запрашивается какой-то оператор, в чем различие запросов в SQL и Билдере?
Это гарантировано, что значение KodSyst всегда будет уникальным в CardTable?
Нужно бы посмотреть работают ли запросы с
...
WHERE CardId IN(1,2)
и
...
WHERE CardId=1
Если оба работают, тогда можно изменить конец кода
cmtkn->CommandText = AnsiString("") +"\
Insert Into " + CardTable +" (KodSyst, GostID, NameRD) \n\
Select KodSyst, GostID, NameRD \n\
From " + SectorTable + " \n\
Where CardID in (" + sql_tkn + ") \n\
insert into "+ CardBreak +" (CardID, Sp20i19) \n\
Select tp2.CardID, tc1.Sp20i19 \n\
From "+ SectorBreak +" tc1 \n\
inner join "+ SectorTable + " tp1 on tc1.CardID = tp1.CardID \n\
inner join "+ CardTable + " tp2 on tp2.KodSyst = tp1.KodSyst \n\
Where tp1.CardID ";
if(bookmarks.size()>1)
cmtkn->CommandText+="in (" + sql_tkn + ")";
else
cmtkn->CommandText+="=" + sql_tkn;
...
WHERE CardId IN(1,2)
и
...
WHERE CardId=1
Если оба работают, тогда можно изменить конец кода
Запрос так работает. Спасибо за подсказку, до этого я не додумалась. Код исправила, теперь ошибка такая:
inner join "+ CardTable + " tp2 on tp2.KodSyst =: tp1.KodSyst \n\
Тут у меня, наверное, ошибка =:, было пропущено.
Запускаю код, выскакивает сообщение:
Как-то все время запросы с параметром я запускаю с помощью компонента TADOQuery. С помощью TADOCommand еще не приходилось. Может не хватает что-то типа:
Мимоходом, если KodSyst уникальный в CardTable, тогда WHERE выражение лишнее.
Да, в CardTable KodSyst - уникальный код.
Потом не можно вместо inner join-ов использовать простой WHERE? Типа:
SELECT tp2.CardID, tc1.Sp20i19
FROM SectorBreak tc1, SectorTable tp1, CardTable tp2
WHERE tp1.CardID IN (sql_tkn)
AND tc1.CardID = tp1.CardID
AND tp2.KodSyst = tp1.KodSyst
String strWhere;
if(bookmarks.size()>1)
strWhere = "IN (" + sql_tkn + ")";
else
strWhere = "=" + sql_tkn;
String str;
str.Format(“INSERT INTO %s(CardID, Sp20i19) \n\
SELECT tp2.CardID, tc1.Sp20i19 \n\
FROM %s tc1, %s tp1, %s tp2 \n\
WHERE tp1.CardID %s \n\
AND tc1.CardID = tp1.CardID \n\
AND tp2.KodSyst = tp1.KodSyst \n\",
CardBreak, SectorBreak, SectorTable,
CardTable, strWhere);
//ShowMessage(str); // для проверки
cmtkn->CommandText = str;
cmtkn->Execute();
}
__finally
{
gtkn->RecNo = crno;
gtkn->EnableControls();
}
str.Format(“INSERT INTO %s(CardID, Sp20i19) \n\
SELECT tp2.CardID, tc1.Sp20i19 \n\
FROM %s tc1, %s tp1, %s tp2 \n\
WHERE tp1.CardID %s \n\
AND tc1.CardID = tp1.CardID \n\
AND tp2.KodSyst = tp1.KodSyst \n\",
CardBreak, SectorBreak, SectorTable,
CardTable, strWhere);
Здесь выдает ошибки, но у меня не получается исправить. В второй строке (“ меняю на (".
И в 7 строке мне не ясно, где же должна закрыться ковычка?
А с остальным я разобралась. Оказывается, я все это хозяйство тестировала на Ацесовской базе. Вот она и не хотела признавать запрос с параметром.
Если написать просто во втором запросе
, то неправильно происходит вставка строк во вторую таблицу.
Если записать, как Вы указывали ранее:
if(bookmarks.size()>1)
cmtkn->CommandText+=" in (" + sql_tkn + ")";
else
cmtkn->CommandText+=" =" + sql_tkn;
указывает на ошибку в строке Where tp1.CardID ";
Самое интересное, что я не знаю, как исправить.
Я так никогда не пишу, поэтому хочу разобраться, в чем ошибка.
str = Format("INSERT INTO %s(CardID, Sp20i19) \n\
SELECT tp2.CardID, tc1.Sp20i19 \n\
FROM %s tc1, %s tp1, %s tp2 \n\
WHERE tp1.CardID %s \n\
AND tc1.CardID = tp1.CardID \n\
AND tp2.KodSyst = tp1.KodSyst \n",
ARRAYOFCONST((CardBreak, SectorBreak, SectorTable,CardTable, strWhere)));
Where CardID in (" + sql_tkn + ")
то неправильно происходит вставка строк во вторую таблицу.
Если добавляется море записей, тогда это может из-за соединений.
Если добавляется море записей, тогда это может из-за соединений.
Да, именно море. С запросом попробую разобраться сама.
А исправленный код пока не имею возможность проверить. Нужно переустановить Билдер дома, какой-то глюк. Мне недавно пришлось заливать компьютер. Так что, если будут вопросы, продолжу в понедельник.
А вообще, огромное спасибо.:) Увидела еще одну форму задания строкового формата.
А о каких соединениях здесь идет речь?
Код работает. Спасибо огромное. С макросом ARRAYOFCONST мне еще не приходилось сталкиваться. Очень удобна такая запись запроса.
Осталось разобраться с "морем записей".