Кто знает подскажите !!!!!
есть БД Access в ней 2 Таблицы:
ФИО(главная) и Адрес(подчиненная)
Key(счетчик)| Key1(счетчик) связь Key-Key1
Фамилия | Город
имя | Улица
Отчество | Дом(квартира)
в Delphi есть форма на которой есть: DBGrid,
6 Edit-тов и кнопки "добавить" и "удалить"
Пользователь вводит в Editы данные нажимает на кнопку "Добавить"
и данные которые он ввел должны добавлятся в таблицы,и
отображаться в DBGride.
как это сделать? и как удалить текущую запись по кнопке "Удалить"?
к БД подключаюсь через ADOTable.
добавляю через ADOQuery запросом
по кнопке "добавить" пишу:
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
28-03-2006 01:19 | Комментарий к предыдущим ответам
Честь и хвала, по истине самый терпеливый.
Это я вчера просто очень добрый был.
А вообще-то обычно я очень злой и раздражительный.
:-)
А что тут разбираться, все очень просто:
- Добавляем запись в первую таблицу, nil ставим потому что поле - счетчик и устанавливать его значение не нужно, оно заполнится автоматически
27-03-2006 14:30 | Комментарий к предыдущим ответам
по указанному вами адресу я был!
там рассматривается пример с телеф.справочником!
а как вы заметили похожего там нет.
Поля подстановок там есть? Реализация есть? Две таблицы есть? Что еще нужно, чтобы понять механизм работы???
Разбейте свою таблицу еще примерно на 5-6 и тогда с целостностью все будет ОК :o)
Не надо смеяться над преподом. Акцесс, конечно, это несерьезно, но вот в MS SQL можно разбить таблицу на несколько более мелких и хранить их физически на разных серверах. В этом случае при ядерном взрыве вероятность полной потери данных сильно уменьшается.
а я и не говорил что надо по две строки для одной фамилии выводить!
это типа для целостности данных сказал препод!
Вот он, момент истины! Через 11 часов обсуждения я начал хоть что-то понимать!
Ну что сказать? Очевидно, что бессмысленно делать две таблицы, если одна фамилия никогда не будет содержать два адреса. Но как объяснить это преподу? Судя по его знаниям в области целостности данных - никак :-(
Остается только сделать так, как хочет препод.
Итак, таблицы:
[ФИО]: Key (счетчик), Фамилия, Имя, Отчество
[Адрес] Key1 (ЧИСЛОВОЕ), Город, Улица, Дом
Еще раз обращаю внимание - поле Key1 в таблице [Адрес] ЧИСЛОВОЕ, а не счетчик!
var
Key: integer;
begin
// ADOTable1 - специально для операций с таблицами
ADOTable1.TableName := 'ФИО';
// Добавляем запись в таблицу [ФИО]
ADOTable1.AppendRecord([nil, Edit1.Text, Edit2.Text, Edit3.Text]);
// Запоминаем значение счетчика
Key := ADOTable1.Fields[0].Value;
ADOTable1.TableName := 'Адрес';
// Добавляем запись в таблицу [Адрес], в качестве поля Key1 используем
// значение счетчика из таблицы [ФИО], чтобы записи в таблицах были связаны
ADOTable1.AppendRecord([Key, Edit7.Text, Edit8.Text, Edit8.Text]);
// ADOQuery связан содержит запрос, объединяющий таблицы, и связан с гридом
// или можно использовать другой ADOTable - без разницы.
// Переоткрываем его, чтобы увидеть вставленные записи.
ADOQuery1.Close;
ADOQuery1.Open;
end;
Код не проверял, возможны мелкие неточности, но суть верна!
27-03-2006 12:11 | Комментарий к предыдущим ответам
это типа для целостности данных
Сначала надо нагородить, а затем побеспокоиться о целостности - ну чтобы задача простой не казалась.
Разбейте свою таблицу еще примерно на 5-6 и тогда с целостностью все будет ОК :o)
Давайте тогда сначала (препологается, что вы уже почитали книжки по совету уважаемого Green-а):
1) Построение БД всегда начинается с изучения предметной области.
У вас есть студенты, которые где-то живут. Неужели вы изначально считаете, что один студент может жить в нескольких местах? Это необоснованное усложнение задачи.
Определимся с зависимостями. Реальная зависимость многие к одному есть между студентами и городом. В одном городе может проживать несколько студентов, но один и тот же студент не может проживать в нескольких городах. Поэтому, чтобы избежать так называемых аномалий вставки, изменения и удаления города необходимо вынести в отдельную таблицу. Пусть это таблица City(id,name). Тогда в основной таблице вы должны вместо поля "город" вставить внешний ключ - допустим idcity. Структура вашей таблицы примет вид: Student(ID, Familiya, Imya, Otchestvo, Address, idсity, Ulica, Dom).
Где поле ID - целое, автоинкрементное, а поле idсity - целое, но не автоинкрементное.
2) Реализация в Делфи: В любой книге про Делфи, где хоть поверхностно затрагивается создание приложений для работы с базами, рассматривается подробно ваш случай. Объяснять на форуме как это делается - проблематично (Получиться целая глава книги). Если у вас нет под рукой книг, воспользуйтесь электронными вариантами (например здесь http://podgoretsky.com/ftp/Docs/Delphi).
3) Если вам бонально лень читать, тогда вам путь на спец. сайты где вам под заказ за довольно невысокую цену все быстренько оформят да так, что любой препод останется доволен.
И самое главное поймите - на форумах за вас никто программировать не будет. Здесь могут подсказать, навести на мысль, кинуть ссылочку, но предоставить готовую программу - извините.
to Сабир Сафаров
не работает!
to Green
структуру таблицы и текст программы почему то не дали :-((((
:-))))))))))
это задание дал препод, за неделю сказал зделать!
да задача так поставленна чтоб данные находились в 2-х и более таблицах!
Ого! Детальная постановка задачи. Количество гридов равное единице тоже в задаче поставлено? А структура таблицы и текст программы случайно в задаче не поставлены - это сильно бы упростило проблему? :-)
А чем обоснована такая постановка задачи? Почему не в одной таблице? Или это лабораторная работа или заказчик шибко грамотный.
Все это, конечно, интересно, но не надо быть программистом, чтобы понять, что вывести в одной строке два адреса проблематично, вывести две одинаковые фамилии в двух строках - тоже криво. Сначала надо бы с интерфейсом разобраться, а потом уже за код браться (стихи опять получились).
27-03-2006 11:07 | Комментарий к предыдущим ответам
Понятно - это какая-то фишка акцессовская. У запроса есть имя - для меня это чудо.
Так, тогда вопрос по другому - вы сделали так как написал Master_NN: создали пару таблиц с полями, которые он написал и т.д. - и не работает?
Green а в чем проблема то ? ну и что что DBGrid один!
Проблема не в том, что грид один, а в том что его не столько же, сколько таблиц. Как можно вывести одним запросом в один грид данные на людей, если у них по нескольку адресов? А если у них по одному адресу, то зачем тогда две таблицы? Налицо фигня :-(
Запрос построил мастером Access, добавил поля которые надо отображать и все!
в ADTable в свойстве TableName указал имя этого запроса !
DataSource настроил на ADOTable, DBGrid на DATASource !
ADOTable.Active:=true.
вот и все !
это что новость ?
DBGrid->DataSource->ADOTable ->Запрос
Это новая методика или просто ЧУДО?
Что вы прописываете в запросе? Что указываете в настройках AdoTable? На какую таблицу настраиваете?
Создайте ребята на форме 150 кнопок... Нет, не то.
Какой вопрос - такой ответ. При добавлении записей запросом тебе тоже придется 150 кнопок делать. Только вряд ли кто-то будет твою идею на практике использовать.
to Леонид Голиков:
DBGrid один
Интересно. Грид один, а таблицы две?
Срочно книгу в руки - и на диван!
2 Green
Ай молодца.
Да хоть десять:
ADOTable1.AppendRecord([Null, Edit1.Text, Edit2.Text, Edit3.Text]);
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
//...еще восемь раз
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
Если автор действительно хочет сделать два грида и во втором выводить адреса выбранного в первом гриде человека (из вопроса это непонятно), то вторую таблицу надо будет фильтровать, либо использовать не ADOTable, а ADOQuery.
Создайте ребята на форме 150 кнопок, и в каждой из них прибавьте по одному
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
В Итоге первая кнопка создаст одну запись в таблице Address
вторая кнопка - 2 записи.
{Ещё 147 кнопок}
150-ая создасть .... ну понимаете.
Нет, не то.
2 Леонид Голиков
Вы уже создали... ?
Начали.
Есть одна таблица FIO с полями (FioID(автоикр.), Familiya, Imya, Otchestvo)
Вторая таблица Address с полями (AddressID (автоикр.), Address, Gorod, Ulica, Dom, FioID int(ключ из таблицы FIO, не Автоинкрементный)).
Green
DBGrid один.
в Accesse создал запрос на отображение данных из 2-х таблиц,и этот запрос прицепил к DBGrid-у через ADOTable.
но с добавлением все же проблема остается!
выдает ошибку 'ADOQuery1: Field 'FioID' not Found'
Field - поле, not found - не найдено.
Брось-ка ты и вправду эту программу, возьми книжку по Дельфи и по базам данных, ложись на диван и почитай часика три. Уверен, эти три часа будут потрачены с гораздо большей пользой, чем последние три дня.
Если я захочу добавить Вторую запись в таблицу Address то что я получу использовав ваш вариант?
Да хоть десять:
ADOTable1.AppendRecord([Null, Edit1.Text, Edit2.Text, Edit3.Text]);
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
//...еще восемь раз
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
Если автор действительно хочет сделать два грида и во втором выводить адреса выбранного в первом гриде человека (из вопроса это непонятно), то вторую таблицу надо будет фильтровать, либо использовать не ADOTable, а ADOQuery.
Green, Если вы не заметили, то это была всего лишь идея...
Нет, не заметил. По объему кода это тянет больше на исчерпывающее решение, чем на просто идею.
Ещё лучше бы использовать транзакции на добавление итд, чем описанный вами AppendRecord.
На фиг здесь транзакции? Если уж так хочется, то никто не мешает использовать транзакции вместе с AppendRecord, только по моему мнению, они здесь совершенно не нужны.
Если вы пытаетесь просто придираться, то другое дело...
Я не придираюсь. Просто мое решение очень простое и наглядное, и я не понимаю зачем делать сложно, когда можно просто?
А Сабир Сафаров совершенно прав. Во-первых, автору надо теорию сначала почитать, а то таких вопросов можно миллион назадавать. А во-вторых, для этой задачи и правда подошла бы одна таблица. Адрес у человека все равно как правило один, а что программа не для китайцев - это мы уже выяснили :-)
27-03-2006 08:11 | Комментарий к предыдущим ответам
to Master_NN:Вывод – используйте собственное ключевое поле во всех без исключения таблицах. Даже если Вам кажется, что без него можно обойтись.
Спорное утверждение, очень спорное...
Пример: Есть таблица Table1(id,name) и таблица Table2(id,name). Между ними существует связь M:N. Вводим третью таблицу Table1_Table2(idTable1,idTable2). Никаких дополнительных полей в ней исходя из предметной области не требуется. Достаточно ввести составной первичный ключ (idTable1,idTable2), чтобы на уровне базы контролировать дублирующиеся строки, или даже лучше прописать триггер, в котором перед вставкой проверять отсутствие необходимой строки.
Послушаем ваш совет и подсчитаем, сколько мы можем сэкономить места если обойдемся триггером. Представьте, что у вас в первой таблице 10^6 записей, во второй 10^6 записей. Получается что если вводить дополнительный первичный ключ, то он должен быть 8 байтовым (bigint или как-там по другому) - итого вы откусываете на винте 8*10^12 байт. Это конечно все очень утрировано (на физическом уровне в БД все сложнее) но все же АЙ-АЙ-АЙ. Так нельзя.
Вывод: все сложнее.
Если я захочу добавить Вторую запись в таблицу Address то что я получу использовав ваш вариант?
ADOTable1.AppendRecord([Null, Edit1.Text, Edit2.Text, Edit3.Text]);
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
А теперь прочитайте что было предложено...
Теперь в первом гриде который отображает данные из ADOQuery1 есть запись, выделив её, можно добавлять записи в таблицу Address кодом
.....
теперь в таблице Address есть запись относящаяся к выбранной в таблице FIO.
......
Теперь должен получиться результат. 2 Грида. Один отображает записи таблицы FIO, а другой Address'a .
Первый раз вижу, чтобы закрывали запрос в гриде, чтобы в него запись добавить!!!
Green, Если вы не заметили, то это была всего лишь идея... Есть ещё такое понятие, как тэмповый Query, или отдельный исполняемый Query, в котором динамически можно отрабатывать все запросы, я не прав? Ещё лучше бы использовать транзакции на добавление итд, чем описанный вами AppendRecord. Уж больно я сомневаюсь что AppendRecord лучшее решение. Если вы пытаетесь просто придираться, то другое дело... Удачи.
27-03-2006 07:43 | Комментарий к предыдущим ответам
ничего непомогает!
я уже 3 дня над этой задачей сижу !
Вы потратите еще больше своего времени, если не разберетесь капитально в структуре реляционных баз (если это конечно вам нужно). Как правильно заметили Green и Master_NN, у вас неправильная структура данных,а ее уже никакими ухищрениями не исправишь.
Действительно, зачем городить весь этот огород с двумя (или тремя) таблицами, их связыванием и т.д. если у вас между ними скорее всего отношение один к одному? Зато "город" является просто полем, а не вынесено в отдельную таблицу. Есть такое замечательное правило в БД: "каждый факт в одном месте" - от него и танцуйте.
PS Много хороших, доступным языком написанных книг на citforum.ru
Настойчиво рекомендую - посмотрите, сэкономите свое время
ничего непомогает!
я уже 3 дня над этой задачей сижу !
мож кто скинет пример рабочий кому не жалко!
Когда я заменил Null на nil (стихи), то у меня все заработало.
Код из двух строк, которые я написал. Напиши свой код, укажи строку, которая выдает ошибку и какая сейчас структура таблиц. Какие компоненты ADOTable с какими таблицами связаны? Убрал ли ты счетчик из второй таблицы?
to _MaSteR_NN_:
Первый раз вижу, чтобы закрывали запрос в гриде, чтобы в него запись добавить!!!
Особенно прикольно будет выглядеть, когда при возникновении ошибки записи запрос закроется и не откроется :-(
И по-моему код из двух строк немного проще, чем из 20, тем более, что при добавлении записи курсор не будет перемещаться на начало грида.
Еще раз повторяю - код с AppendRecord - рабочий. Просто надо разобраться со структурой БД и с тем, что за интерфейс делает автор вопроса. Не усложняйте код там где это не нужно, он сам где надо усложнится :-)
Начали.
Есть одна таблица FIO с полями (FioID(автоикр.), Familiya, Imya, Otchestvo)
Вторая таблица Address с полями (AddressID (автоикр.), Address, Gorod, Ulica, Dom, FioID int(ключ из таблицы FIO, не Автоинкрементный)).
Вставляем данные в таблицу FIO
ADOQuery1.Close; //Закрываем таблицу
ADOQuery1.SQL.Text := 'Insert into FIO(Familiya, Imya, Otchestvo) values (:Familiya, :Imya, :Otchestvo) '; // Запрос
ADOQuery1.Parameters.ParamByName('Familiya').Value := Edit1.Text; //
ADOQuery1.Parameters.ParamByName('Imya').Value := Edit2.Text; //
ADOQuery1.Parameters.ParamByName('Otchestvo').Value := Edit3.Text; //параметр
ADOQuery1.ExecSQL; // запрос на выполнение
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'Select * from FIO'; // возвращаемый результат
ADOQuery1.Open;
Теперь в первом гриде который отображает данные из ADOQuery1 есть запись, выделив её, можно добавлять записи в таблицу Address кодом
как в третьей таблице указать отношения менжду 1-й и 2-й ???
Тогда поле Key1 надо оставить типа "счётчик" и сделать третью таблицу с полями Key и Key1. После вставки записей в таблицы [ФИО] и [Адрес] новые значения счётчиков вставляются соответственно в поля Key и Key1 третьей таблицы. Но это только если нужно обеспечить отношение "многие-ко-многим". Как я уже говорил, если программа не для китайцев, достаточно двух таблиц :-)
2 Green
А собственно зачем?
Во-первых
Как минимум "правило хорошего тона" в построении баз данных...
Во-вторых
Ключевое поле – это такое поле (или набор полей) по содержимому которого можно однозначно идентифицировать запись таблицы. Т.е. по значению ключевого поля всегда однозначно можно сказать о какой записи идет речь и не может существовать 2 записей с одинаковыми значениями ключевого поля.
На первый взгляд, вопрос может показаться странным. Разве можно без ключевого поля? Оказывается, в некоторых случаях можно.
Например, для организации связи много-ко-многим стандартным способом является создание таблицы-посредника. Что имеется в виду?
Допустим, у Вас есть список контрагентов и список банков. Разумеется, один и тот же контрагент может иметь счет в нескольких банках. Но верно и обратное – один банк работает с несколькими контрагентами. В этом случае Вы не можете сделать внешний ключ банка в таблице контрагента или внешний ключ контрагента в таблице банков. Вам необходимо ввести таблицу-посредник, которая будет хранить в себе внешний ключ банка и внешний ключ контрагента.
При такой организации, каждая запись в этой таблице посреднике однозначно идентифицируется парой значений: код контрагента-код банка. Поэтому возникает искушение не вводить еще одно поле для суррогатного ключа этой таблицы-посредника.
Однако я настоятельно рекомендовал бы Вам вводить-таки собственное ключевое поле для всех таблиц базы данных. Почему? Ну, потому, что любая программа имеет «привычку» развиваться.
Если вернуться к примеру с контрагентами и банками, то легко заметить, что я обошел вниманием тот момент, что один контрагент может иметь несколько счетов в одном и том же банке. Этот самый реквизит (счет контрагента в банке) невозможно прицепить ни к банку, ни к контрагенту. Но он очень удачно подходит к этой таблице-посреднику. Если бы для идентификации записи в этой таблице Вы опирались бы на пару: код банка – код контрагента, то Вам пришлось бы серьезно переделывать значительную часть программы. А в случае существования собственного кода записи никаких проблем. Ну, добавили еще одно поле, ну и что?
В данном случае я рассмотрел достаточно очевидный случай, но зачастую кажется, что по-другому быть не может и уж вот здесь-то собственный идентификатор записи не нужен. Не обольщайтесь. Если Вам кажется, что чего-то не может быть – это всего-лишь значит, что Вы чего-то не знаете.
Вывод – используйте собственное ключевое поле во всех без исключения таблицах. Даже если Вам кажется, что без него можно обойтись.
делаю без запроса
ADOTable1.AppendRecord([Null, Edit1.Text, Edit2.Text, Edit3.Text]);
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
выдает ошибку 'Field 'Key1' kannot be modified'
поле Key1 -счетчик(ключевое) в таблице ФИО.
в чем проблема ??
открываю Access в ФИО все добавил а 2-я табл. пустая !
и как в третьей таблице указать отношения менжду 1-й и 2-й ???
MasterID в первой таблице счетчик.(ключевое) правильно ?
Абсолютно.
MasterID во второй таблице число (совпадения допускаются так ?)
ага, допускаются, и даже обязательно. А заполняться они будут по мере заполнения таблицы Detail. То есть это номер ФИО к которому будет относиться Detail информация. (а как её выбирать я уже показывал.)
а во второй таблице нужно ключевое поле или нет ?
Нужен. Можно Автоинкрементное.
В Акцессе это называется "счётчик". Если ты хочешь сделать связь "многие-ко-многим" (фамилия может иметь много адресов, адрес может иметь много фамилий), то у тебя должны быть две таблицы с ключевыми полями - счётчиками и третья таблица с двумя полями (Key, Key1), которая будет хранить отношения между первыми двумя таблицами.
Если ты хочешь сделать связь "один-ко-многим" (на одну фамилию много адресов), то во второй таблице ключевое поле должно быть не "счётчик", а "числовой". Значение этого поля должно заполняться не автоматически, как сделано у тебя сейчас, а вручную тем значением, которое было сгенерировано счётчиком при вставке строки в первую таблицу.
Если не использовать запросы, то код сильно упрощается, примерно так:
ADOTable1.AppendRecord([Null, Edit1.Text, Edit2.Text, Edit3.Text]);
ADOTable2.AppendRecord([ADOTable1.Fields[0].Value, Edit7.Text, Edit8.Text, Edit8.Text]);
MasterID в первой таблице счетчик.(ключевое) правильно ?
MasterID во второй таблице число (совпадения допускаются так ?)
а во второй таблице нужно ключевое поле или нет ?
Привет!
2 Леонид Голиков
а что знаит автоинкрементные ??? и на что это влияет ?
Это значит что при каждой вставки записи в таблицу автоинкрементное поле будет увеличиваться автоматически(по умолчанию на единицу.)
Так вот. Если есть две таблицы, которые должны быть связаны между собой, то это означает что они должныы быть связаны по какому-нибудь полю.
Например.
есть таблица Master (MasterID {может быть автоинкрементным}, MasterName)
и есть таблица Detail (DetailID, DetailName, MasterID{Вот по этому полю они и будут связаны} )
Например, при выборке, нам нужно что бы в гриде показывались записи которые относятся к выбранному полю из таблицы Master. Тогда просто делаете запрос
SELECT * FROM Detail WHERE Detail.MasterID = Master.MasterID
Вот таким спобом и связываются таблицы, и эта связь называется один-ко-многим. То есть на одну Master запись будут добавляться записи в Detail, относящиеся к Master по ключу MasterID ...
Так будет и в вашем случае, где к таблице ФИО будет относиться таблица Адрес. То есть на одну запись из Таблицы ФИО можно будет повесить несколько адресов.
Исходя из этого у вас в таблице Адрес должно быть связующее поле из таблицы ФИО.
Перечитал еще раз внимательно вопрос: есть БД Access в ней 2 Таблицы
Как же они связаны, если нет третьей таблицы, а оба ключевых поля автоинкрементные? Похоже они связаны только в мыслях автора вопроса, но для Дельфи этого недостаточно :-)
Нужно, чтобы поле Key1 было целое (не счетчик!) и ссылалось на Key.
Если таблицы всего две, то много людей жить в одной квартире не могут. Все-таки эта программа не для китайцев и не для студентов :-)))
27-03-2006 04:03 | Вопрос к автору: запрос дополнительной информации
Поле key у вас автоинкрементное? Как вы узнаете что проставлять в поле key1? Т.е. из приведенного вами кода непонятно как вы осуществляете связывание при вставке. Или вы что-то не дописали, или ошибочка...
ЗЫ Попробуйте замечательные клавишы F7,F8...
В вашем случае данные в гриде надо обновить. Т.е. после вставки или удаления, сделать для датасета, который отображает ваш грид Requery.
to Green: "Что, есть люди, у которых два адреса? Или слишком много людей живут в одной квартире (программа для китайцев)". Например, студенты (почти как китайцы) - у них есть два адреса - домашний и временный в общаге. И в общаге в комнате может жить много студентов.
Во-первых, зачем две таблицы для людей и для адресов? Что, есть люди, у которых два адреса? Или слишком много людей живут в одной квартире (программа для китайцев) :-)))
Во-вторых, не советую формировать запросы таким образом, потому что очень легко запутаться. Например, зачем тут код, который я подчеркнул:
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.