Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Базы данных и репортинг > Как вывести запрос состоящий из двух таблиц


Автор: Chechaco 20.10.2005, 05:05
Здравствуйте, вопро с следующий:
Написал я запрос для TQuery
Код

Select Field1, Field2, Field1Table2 from Table1, Table2
Order by Field1, Field2


Причем в Table1 есть данные а Table2 пустая, в результате мне выдается запрос с одним пустым полем. Если объединяю два запроса через UNION - выдает ошибку. Как сделать чтобы в запросе выводились все значения полей из Table1 и рядом, соответственно, пустые поля из Table2?

Автор: offline 20.10.2005, 13:31
А у таблиц есть общие поля?

Автор: Alex 20.10.2005, 14:01
При объединении через union все поля в о обоих выборках должны иметь одинаковый тип и их кол-во должно быть равным

Автор: Самурай 20.10.2005, 15:11
Код

SELECT * FROM Table1 
LEFT JOIN Table2 ON Table1.id=Table2.id;

Проверено на базе данных Microsoft Access, откуда получен вывод, что должно работать на других базах данных.

P. S.
Table1 запелнена, а Table2 не заполнена. В противном случае меняется слово LEFT на слово RIGHT, что можно без труда сделать при автоматической генерации SQL-запроса в программе, т. е. преварительно посмотрев, какая из таблиц является пустой.

Автор: Chechaco 21.10.2005, 04:08
Спасибо, получилось!
То есть, если я правильно понял, чтобы объединить две таблицы (Paradox) в одном запросе у них должны быть общие ключевые поля? Других ограничений для объединения нет?

Автор: offline 21.10.2005, 10:57
Да, что бы включть несколько таблиц в запрос, нужно, что бы они были связанны между собой, но не обязательно ключевыми полями. если Table1.id=Table2.id ID ключевое поле, а таблицы связанны не этими полями, то результат запроса буден неверным smile

Автор: Chechaco 21.10.2005, 17:41
А может еще подскажете как вводить данные в таблицу через DBGrid -> Query без дополнительных действий типа нажимания кнопки после ввода, чтобы данные сохранялись в таблице просто после перехода в гриде на другую ячейку (или хотя бы по нажатию Enter)? Благодарю.

Автор: Самурай 21.10.2005, 20:18
Цитата(Chechaco @ 21.10.2005, 18:41)
или хотя бы по нажатию Enter

Так что ли?
Код

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
 if key = #13
  then
   Query1.Post
end;



Цитата(kirilllius @ 21.10.2005, 11:57)
ключевыми полями.

А если просто создать поле, которое всегда будет равняться единице у двух таблиц? Как в этом случае?

Автор: YurikGL 22.10.2005, 18:29
Цитата
procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
if key = #13
  then
   Query1.Post
end;


Ну-ну.... по Enter осуществляется вход в редактирование поля записи (во всяком случае в EhGrid), и если оказалось, что заполнены не все поля и среди незаполненных остались обязательные к заполнению, будет Exception...

Гораздо лучше post делать по закрытию окна, где редактировались данные.

Цитата
А если просто создать поле, которое всегда будет равняться единице у двух таблиц? Как в этом случае?

Мммм.... зачем такое.....???

Автор: offline 22.10.2005, 19:20
Цитата

А если просто создать поле, которое всегда будет равняться единице у двух таблиц? Как в этом случае?

Тогда для связки таблиц лучше не использовать такое поле smile что-бы дров не наломать и головной боли было меньше. Заводи в каждой таблице ключевое автоинкременируемое поле и связывай его с любым полем подчененной таблицы 100% без заморочек.

Цитата
чтобы данные сохранялись в таблице просто после перехода в гриде на другую ячейку

Обрати внимание на пост YurikGL он верно сказал
Цитата
Гораздо лучше post делать по закрытию окна, где редактировались данные.

Данные в сетки лучше не редактировать, это не очень хорошо smile Пользователь может ткнуть случайно или еще что нибудь, а данные уже не вернешь smile Лучше для редактирования создавать специальное окно в котором по нажатию например на кнопочки " Принять" данные будут переноситься в таблицу, а если не нужно то просто закрыть окошко или сделать кнопочку "Отменить" которая вызовет Close. А на сетки лучше установить свойство "Только для чтения"

Автор: YurikGL 22.10.2005, 20:56
Цитата
Гораздо лучше post делать по закрытию окна, где редактировались данные.

Добавлю, что надо это делать в OnCloseQuery примерно так:

try
Table.post
except
on e:exception do begin
canclose:=false;
raise Exception.Create('Не могу подтвердить изменения записи. Произошла ошибка'+#13+e.Message);
end;

З.Ы. это в том случае, если все же решишь редактировать в сетке...

Автор: offline 22.10.2005, 21:07
Лучше вешать на отдельную кнопку. Я например хочу закрыть окно не сохраняя изменений. Да и использовать компоненты не связанные с DB, а простые. Хотя это все дело вкуса smile

Автор: YurikGL 22.10.2005, 21:51
Цитата
Лучше вешать на отдельную кнопку. Я например хочу закрыть окно не сохраняя изменений. Да и использовать компоненты не связанные с DB, а простые. Хотя это все дело вкуса 

Тогда уж Firebird + прямое управление транзакциями smile И можно DB-компоненты пользовать.

Автор: Chechaco 24.10.2005, 03:43
Так, а теперь по порядку. Я поставил Query, подцепил к ней базу, Поставил DataSource, поставил DBGrid, соединил все это дело. В Query написал
SELECT * FROM Table1
LEFT JOIN Table2 ON Table1.id=Table2.id; (по совету Самурая)
Поставил RequestLive = true, Active = true
Начинаю редактировать - а оно не редактируется, в то время как с выборкой из одной таблицы все проходит на ура. Т.е. я так понимаю должен быть какой-то другой выход, а какой? И еще, как сделать чтобы в выборке из двух таблиц (master-detail) запись, введенная в detail-таблицу соответствовала по внешнему ключу записи в master-таблице напротив которой она была введена?

Цитата(kirilllius @ 22.10.2005, 19:20)
Данные в сетки лучше не редактировать, это не очень хорошо smile Пользователь может ткнуть случайно или еще что нибудь, а данные уже не вернешь smile


В моем случае это нет суть важно, на крайний случай все данные есть на бумаге, главное не ставить кнопку "Удалить базу" smile

Автор: Grig 24.10.2005, 04:02
Цитата(Chechaco @ 24.10.2005, 03:43)
Начинаю редактировать - а оно не редактируется

А что именно не редактируется?
Может ошибку выдает какую-нибудь?
Query1.Post стоИт?

Автор: Chechaco 24.10.2005, 04:14
Вообще не дает редактировать данные в Гриде т.е. не вставить не изменить.

Query1.Post у меня стоить в OnCloseQuery:

Цитата(YurikGL @ 22.10.2005, 20:56)

try
Table.post
except
on e:exception do begin
canclose:=false;
raise Exception.Create('Не могу подтвердить изменения записи. Произошла ошибка'+#13+e.Message);
end;


Правда в этом случе если закрыть Query без ввода то вылетает сообщение Query1: DataSet not in edit or insert mode. Мол Кверя не была в режме редактирования и т.д.

Автор: offline 24.10.2005, 09:59
Для того, чтобы всё это нормально работало, нужно, чтобы в TQuery были включены RequestLive и CashedUpdates. Соответственно, для
подтверждения изменений нужно вызывать TQuery.ApplyUpdates и
TQuery.CommitUpdates, либо TDatabase.ApplyUpdates, а для отмены -
CancelUpdates.
Добавлено @ 10:04
Цитата
Правда в этом случе если закрыть Query без ввода то вылетает сообщение Query1: DataSet not in edit or insert mode


Так и будет, т.к. ты пытаешься применить метод Table.post для таблицы не переведеную в редактирование. Перед тем как вызвать Table.post, проверь, состояние набора данных и если он не в режиме просмотра, то вызывай Table.post, а если в режиме просмотра, то ничего не делай, тогда и ошибки не будет.

Код

if not (ADOTable1.State = dsBrowse)
 then ADOTable1.Post;

Автор: Chechaco 24.10.2005, 11:17
RequestLive и CashedUpdate у меня включены.

Цитата(kirilllius @ 24.10.2005, 09:59)
для
подтверждения изменений нужно вызывать TQuery.ApplyUpdates и
TQuery.CommitUpdates, либо TDatabase.ApplyUpdates, а для отмены -
CancelUpdates.


А где это вызывать?

На счет Query.Post спасибо, помогло smile

Автор: offline 24.10.2005, 11:26
Это вызывается тогда, когда тебе нужно принять изменения. Если ты принимаешь их когда закрываешь запрос, вот туда и вешай.

Автор: Chechaco 25.10.2005, 04:19
Все равно не изменяется. Я поставил TUpdateSQL, сгенерировал в нем запросы на изменение, написал TQuery.ApplyUpdates в таком виде:
Код

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if not (Query1.State = dsBrowse) then
begin
try
Query1.post;
Query1.ApplyUpdates;
except
...


теперь я могу изменять данные в таблице, но при выходе изменения не сохраняются.

Автор: Grig 25.10.2005, 06:18
Ну вот например как я делал:
перед закрытием просто прогонял в цикле по всем записям и записывал их в базу данных.

Код

Query1.First;
    while not Query1.Eof do
     begin
Query1.Edit;
  Query1.FieldByName('aaa').Asstring:=DbGrid1.Fields[1].Value ;
Query1.Post;
end;


Правда наверное, бабушкин метод.. Зато работает!!

Автор: Chechaco 25.10.2005, 07:21
Все равно ничего не сохраняется, может потому что в запросе одновременно 2 таблицы, у меня даже автоинкремент не создается при вводе новой записи.

Автор: offline 25.10.2005, 09:46
Если ты работаешь с ADO, то чтобы увидеть изменение в таблицах после запроса на изменение то нужно их переоткрыть. Это можно сделать например так ADOTable1.Requery;


Автор: Chechaco 25.10.2005, 18:23
Нет. я работаю (точнее пытаюсь работать) с BDE-Paradox7
Мне уже не до запросов с двумя таблицами, хотя бы в простейшем запросе в одной таблице понять как редактируются данные через Query.

Запрос пишу такой:
SELECT * FROM Table1
ORDER BY Pole1

Вводить данные могу, а сохранять - нет, и инкремент, как я уже говорил, не создается, причем никакие ApplyUpdate и Post не помогают.
Хотя если убрать сортировку по Pole1 - можно и редактировать и сохранять, и инкремент создается smile smile

Автор: YurikGL 25.10.2005, 18:38
Цитата
Хотя если убрать сортировку по Pole1 - можно и редактировать и сохранять, и инкремент создается

Если я не ошибаюсь, то Query не предназначен для редактирования т.к. там может быть хитрый запрос, результаты которого редактировать принципиально нельзя. Например, если в одном из полей будет сумма других полей. Система отрабатывает это примерно так: Если набор данных в query точно можно редактировать (select * from) то редактирование разрешается. Если у системы есть подозрение, что редактировать нельзя, то идет запрет на редактирование. Это - мое ИМХО, основанное на опыте и не подтвержденное точными теоритическими знаниями.
Автору: Я бы для редактирования использовал Table-ы с lookup полями. Или вообще стандартные edit-ы (не db) и посылал бы команды на сервер типа 'insert into' или 'update table'. Эти команды формируются на основе текстов из едитов.
Что-то типа
'Insert into table1 (pole1) values '+Edit1.text;

Автор: offline 25.10.2005, 19:59
Так я не понял, то ты пишешь запрос на обновление данных, то ты просто форимруешь набор, а потом пытаешься его отредактировать и куда то сохранить. smile
Что там у тебя за задача?

Автор: Chechaco 26.10.2005, 08:56
Запрос на обновление я пишу в любом случае, в UpdateSQL, но я так понял, обновление через Query не работает даже при простейшей сортировке, YurikGL примерно то же говорил. Может быть потому что автоинкремент в таком случае идет не по порядку.
Сделать я хочу следующее: есть таблица со значениями (Мастер), есть пустая таблица (Деталь), мне нужно в одном Гриде (или как-нибудь так) отобразить значения мастер-таблицы и напротив них вводить значения в деталь-таблицу, так, чтобы автоматически создавались связи мастер-деталь.

Автор: offline 26.10.2005, 10:08
А почему бы не сделать это в двух таблицал, в первой выводишь мастеров, а во вторую детали и связывешь отношением один ко многому, т.е. одному мастеоу соответствует множество деталей. Тут м будут создаваться автоматически связи мастер-детали.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)