Russian Qt Forum

Qt => Базы данных => Тема начата: TukiNov от Сентябрь 04, 2006, 14:00



Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 04, 2006, 14:00
Уф, наконец то зарегился на форуме :)
есть две таблицы :
Код:

CREATE TABLE db_termin (
    `ID` int(11) NOT NULL auto_increment,
    `FULL_NAME` text,
    `SHORT_NAME` text,
    `RAZDEL` int(11) default NULL,
    `P_RAZDEL` int(11) default NULL,
    `OPREDELENIE` longblob default NULL,
   PRIMARY KEY (`ID`)
);

CREATE TABLE db_razdel (
`R_ID` int(11) NOT NULL auto_increment,
`R_NAME` text,
PRIMARY KEY (`R_ID`)
);

Они связаны так : db_termin.RAZDEL=db_razdel.R_ID
Мне нужно чтобы  вместо RAZDEL int(11) в таблице выводился R_NAME text
Можно так сделать при помощи QSqlCursor ?
p.s. Если делать выборку так :
Код:

QSqlSelectCursor *q = new QSqlSelectCursor("select * from db_termin, db_razdel where db_termin.RAZDEL=db_razdel.R_ID");

    QDataTable *t = new QDataTable(q, TRUE, &w);
    q->select();
    t->refresh();

то всё ок, но перестаёт работать terminTable->setFilter( "RAZDEL='" + QString::number(id) + "'" );  который мне очень нужен.
Помогите плиз.
Кто ничего не понял, говорю проще : Как с помощью QSqlCursor сделать выборку из двух связанных таблиц :)


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: SLK от Сентябрь 04, 2006, 14:27
попробуй в select оставить where пустым ... т.е. примерно так

select * from db_termin inner join db_razdel on db_termin.RAZDEL=db_razdel.R_ID


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 04, 2006, 14:40
Цитата: "SLK"
попробуй в select оставить where пустым ... т.е. примерно так

select * from db_termin inner join db_razdel on db_termin.RAZDEL=db_razdel.R_ID

не пашет.
У меня фильт базы происходит при выборе в ComboBox :
Код:

void main_form::filter_by_razdel()
{
    int id;
    mapRazdel( razdelCBox->currentText(), id, FALSE );
    if(id){
terminTable->setFilter( "RAZDEL='" + QString::number(id) + "'" );
    }
    terminTable->refresh();
}

При QSqlCursor, в designer вот что :
Код:

void main_form::polish()
{
    if ( terminTable ) {
        QSqlCursor* cursor = terminTable->sqlCursor();
        if ( !cursor ) {
            cursor = new QSqlCursor( "db_termin", TRUE, db_razdelConnection );      
            if ( terminTable->isReadOnly() )
                cursor->setMode( QSqlCursor::ReadOnly );    
            terminTable->setSqlCursor( cursor, FALSE, TRUE );    
        }
        if ( !cursor->isActive() )
            terminTable->refresh( QDataTable::RefreshAll );
    }
    QMainWindow::polish();
}


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: SLK от Сентябрь 04, 2006, 16:25
дело в том, что текст установленный в setFilter, QT вставляет в раздел  WHERE ....  грубо пересобирая текст запроса примерно таким кодом ....
Код:
  
    QString fieldList = toString( d->nm );
    if ( fieldList.isEmpty() )
return FALSE;
    QString str= "select " + fieldList;
    str += " from " + d->nm;
    if ( !filter.isEmpty() ) {
d->ftr = filter;
str += " where " + filter;
    } else
d->ftr = QString::null;
    if ( sort.count() > 0 )
str += " order by " + sort.toString( d->nm );
    d->srt = sort;
    return exec( str );

По этому возможно, что при сложном запросе (с несколькими таблицами) фильтр в курсоре работать нормально не будет ...

попробуй использовать мой вариант запроса и поставить в код
такой вариант фильтра
Код:
terminTable->setFilter( "db_termin.RAZDEL='" + QString::number(id) + "'" );
 

если и это не сработает, придётся искать другие варианты решения ...


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 04, 2006, 17:43
не работает .... :(


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: SLK от Сентябрь 05, 2006, 10:20
Ну ещё есть пару вариантов для курсора ..... к примеру
для твоего запроса
Код:
select * from db_termin, db_razdel where db_termin.RAZDEL=db_razdel.R_ID
попробовать использовать такой вот фильтр ...
Код:
terminTable->setFilter( "db_termin.RAZDEL=db_razdel.R_ID and db_termin.RAZDEL='" + QString::number(id) + "'" );

Ещё один вариант это создать VIEW на стороне SQL сервера .....
Код:
CREATE VIEW db_termin_razdel
AS select * from db_termin inner join db_razdel on db_termin.RAZDEL=db_razdel.R_ID

и в курсоре открывать этот view ....
Код:
QSqlSelectCursor *q = new QSqlSelectCursor("select * from db_termin_razdel");


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 06, 2006, 00:23
Цитата: "SLK"

Ещё один вариант это создать VIEW на стороне SQL сервера .....
Код:
CREATE VIEW db_termin_razdel
AS select * from db_termin inner join db_razdel on db_termin.RAZDEL=db_razdel.R_ID


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


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: bigirbis от Сентябрь 06, 2006, 08:40
При этом создается а-ля виртуальная таблица, данные которой нельзя редактировать. При чем, данные в столбцах могут быть реальными или вычисляемыми. Обычно это сджойненые таблицы.

А вообще, смотри http://www.sql.ru.


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 07, 2006, 01:15
Спасибо, работает, но не думаю что это устроит заказчиков, попробую ещё подумать :)


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 08, 2006, 12:39
Цитата: "TukiNov"
Цитата: "SLK"

Ещё один вариант это создать VIEW на стороне SQL сервера .....
Код:
CREATE VIEW db_termin_razdel
AS select * from db_termin inner join db_razdel on db_termin.RAZDEL=db_razdel.R_ID


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

Так и знал, у них этот запрос не выполняется, версия MySQL ниже 5, обновлять нельзя.
Вот терь х.з. чё делать :(


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: Grigory от Сентябрь 13, 2006, 14:52
Может быть есть смысл попробовать использовать вычисляемые поля?  Это конечно уменьшит быстродействие, но позволит решить проблему. Нужно переопределить  функцию
Код:
QVariant QSqlCursor::calculateField ( const QString & name ) [virtual protected] 
и добавить вычисляемый столбец в курсор.


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 13, 2006, 20:47
Цитата: "Grigory"
Может быть есть смысл попробовать использовать вычисляемые поля?  Это конечно уменьшит быстродействие, но позволит решить проблему. Нужно переопределить  функцию
Код:
QVariant QSqlCursor::calculateField ( const QString & name ) [virtual protected] 
и добавить вычисляемый столбец в курсор.

эээ, чё то я ничего не понял :)


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: Grigory от Сентябрь 15, 2006, 16:10
Короче, читаешь вначале Ассистант на пример испоьлзования вычисляемых полей в SQL курсоре (там не очень много) Потом нужно будет переопределить функцию QSqlCursor::calculateField. Она объявлена как virtual protected, следовательно, придется создавать свой класс, отнаследовавшись от QSqlCursor. Дальше надо объявить и написать реализацию функции calculateField. Реализация примерно такая будет:
Код:

QVariant YourSqlSelectCursor::calculateField(const QString & name)
{
 QVariant res = QVariant::Invalid;
 if(name=="R_NAME")
 {
    QSqlQuery query("SELECT R_NAME from db_razdel  WHERE R_ID="+value("RAZDEL"));
     if(query.exec())
     {
           res = query.value(0);
     }
 }
 return res;
}


собственно при создании своего курсора q надо добавить в него вычисляемый столбец R_NAME. И при любом обращении к R_NAME будет выполняться функция  calculateField(); Добавление вычисляемого столбца можно сделать например так:
Код:
 q.addField(QSqlFieldInfo("R_NAME"));
 q.setCalculated ( "R_NAME", true );

Ну и саму таблицу заполнять только полями из db_termin
Код:
YourSqlSelectCursor *q = new YourSqlSelectCursor("select * from db_termin);


Вот как-то так. Код конечно не тестировал, так что могут быть ошибки.


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 27, 2006, 16:41
Такс, в простом случае получается. Посмотрел пример из qt/examples.
Но проблема вот терь какая, я всё делал в desiner'е и соответственно таблица уже есть.
вот что в примере (переделанный под мой случай):
Код:

InvoiceItemCursor::InvoiceItemCursor() :
    QSqlCursor( "db_termin" )
{
    QSqlFieldInfo productName( "razdel_name", QVariant::String );
    append( productName );
    setCalculated( productName.name(), TRUE );
}


QVariant InvoiceItemCursor::calculateField( const QString & name )
{
    if ( name == "razdel_name" ) {

QSqlQuery query( "SELECT R_NAME FROM db_razdel WHERE R_ID=" +
    field( "RAZDEL" )->value().toString() );
if ( query.next() ){
   return query.value( 0 );
}
        if(!query.isActive()){
query.lastError().showMessage();}
    }

    return QVariant( QString::null );
}

создаю класс :
Код:

class InvoiceItemCursor : public QSqlCursor
{
    public:
InvoiceItemCursor();
    protected:
QVariant calculateField( const QString & name );
};

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

InvoiceItemCursor invoiceItemCursor;
terminTable->setSqlCursor(&invoiceItemCursor);
terminTable->addColumn("FULL_NAME", "NAME");
terminTable->addColumn( "razdel_name", "R_NAME" );

Собирается всё на ура, а вот когда запускаю, всё падает с сегментацией. В чём дело ? как прикрутить всё это к уже существующей таблице ?
используемый пример лежит тут : qt/examples/sql/overview/subclass3/


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: bigirbis от Сентябрь 27, 2006, 18:43
Похоже на то, что у тебя дохнет курсор, выходя из области видимости.


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: Alex03 от Сентябрь 28, 2006, 05:58
Не знаю как MySQL но некоторые СУБД поддерживают такой вложенный запрос:

select a, b, (select name from tab2 where tab2.id=tab1.ref_id) as c, d from tab1 where ...
Може поможет.

В отличаи от джойнов этот внутренний select выполняется на этапе фетча со всеми + и -
т.е.
- Ошибка может вылезти уже во время фетча.
+ Сам (главный) запрос выполняется быстро.


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: bigirbis от Сентябрь 28, 2006, 08:42
Отсутствие подобной функциональности мне пока попалось только в Firebird


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: Вячеслав от Сентябрь 28, 2006, 14:02
Цитата: "bigirbis"
Отсутствие подобной функциональности мне пока попалось только в Firebird

Мдя ? Месье давно его(птица) видел ? Не надо клеветать - есть оно там .


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: bigirbis от Сентябрь 28, 2006, 14:27
В 1.5 не попадалось


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: Вячеслав от Сентябрь 28, 2006, 19:30
Цитата: "bigirbis"
В 1.5 не попадалось

ну уже 2 есть ;) собственно и в 1.5.3 оно кажись было(но могу ошибаться)


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: TukiNov от Сентябрь 29, 2006, 00:32
Цитата: "Вячеслав"
Цитата: "bigirbis"
В 1.5 не попадалось

ну уже 2 есть ;) собственно и в 1.5.3 оно кажись было(но могу ошибаться)

мне от этого не легче

добавлено спустя 4 часа 25 минут:

 О великий google  :D  :D  как я был слеп  :oops:  :oops:
всего навсего :
в заголовочном файле :
Код:

class InvoiceItemCursor : public QSqlCursor
    {
        public:
         InvoiceItemCursor();
       protected:
            QVariant calculateField( const QString & name );
    };
class Form1 : public QMainWindow
{
    Q_OBJECT

public:
    Form1( QWidget* parent = 0, const char* name = 0, WFlags fl = WType_TopLevel );
    ~Form1();
    [b][u]InvoiceItemCursor * invoiceItemCursor;[/u][/b]
protected:

protected slots:
    virtual void languageChange();

private:
    void init();

};

в cpp :
Код:

InvoiceItemCursor::InvoiceItemCursor() :
    QSqlCursor( "db_termin" )
{
    QSqlFieldInfo productName( "razdel_name", QVariant::String );
    append( productName );
    setCalculated( productName.name(), TRUE );
}


QVariant InvoiceItemCursor::calculateField( const QString & name )
{
    if ( name == "razdel_name" ) {

QSqlQuery query( "SELECT R_NAME FROM db_razdel WHERE R_ID=" +
    field( "RAZDEL" )->value().toString() );
if ( query.next() ){
   return query.value( 0 );
}
        if(!query.isActive()){
query.lastError().showMessage();}
    }

    return QVariant( QString::null );
}

и присваеваем таблице курсор :
Код:

invoiceItemCursor = new InvoiceItemCursor;
terminTable->setSqlCursor(invoiceItemCursor);


Название: QSqlCursor и связанные таблицы. QT 3.3.6
Отправлено: bigirbis от Сентябрь 29, 2006, 09:38
Принципиально от твоего прошлого варианта этот отличается только тем, что создается указатель на курсор (в прошлом ты в качестве аргумента передавал ссылку на курсор - по выходе из области видимости он подыхал - распространенная ошибка).