crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> просмотр таблицы с меняющимися данными, запоминание и выделение тек строки
Steklova Olga
  опции профиля:
сообщение 3.2.2012, 21:20
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Всем привет! ;)
Есть у меня две таблицы БД: T1 и T2, в каждой есть поля ID INTEGER (PK, автоинкрементное) и PARAM FLOAT. Для работы с таблицами использую QSqlTableModel и QTableView.

Во время работы программы в таблицу T1 записи только добавляются.
Организую заполнение и просмотр следующим образом:
- при поступлении первой записи добавляю ее в таблицу БД, выполняю select для модели, первую строку таблицы делаю текущей, запоминаю соотв. значение ID,
- при поступлении следующей записи добавляю ее в таблицу БД, выполняю select для модели, строку с запомненным ID делаю текущей, делаю скроллинг отображения для обеспечения видимости текущей строки,
- при изменении текущей строки оператором запоминаю значение ID. Тут все OK.

А вот с таблицей T2 посложнее...
Во время работы программы, периодически (вероятно, не чаще, чем 1 раз в 5 сек), для занесения в таблицу T2 приходит сразу целый массив записей (размер массива - от одной до 200 записей). Мне надо хранить в БД данные только последнего массива.
Данные разных массивов:
- могут полностью совпадать,
- могут отличаться всеми значениями,
- могут отличаться несколькими значениями,
- могут отличаться количеством значений.
Организую заполнение и просмотр следующим образом:
- при поступлении первого массива добавляю поступившие записи в таблицу БД, выполняю select для модели, первую строку таблицы делаю текущей,
- при поступлении следующего массива удаляю все записи из таблицы БД, добавляю поступившие записи в таблицу БД, выполняю select для модели, первую строку таблицы делаю текущей (пока так).

Как здесь просматривать таблицу с запоминанием и выделением текущей строки?
1) Запоминать ID текущей строки? Здесь это не поможет, так как поле автоинкрементное.
2) Сделать поле ID не автоинкрементным, не удалять предыдущий массив и добавлять новый, а обновлять массив? Этот вариант мне совсем не нравится, по-моему, он очень сложный.
3) Запоминать PARAM текущей строки, а при поступлении следующего массива искать в нем запись с запомненным PARAM и делать ее текущей? А если такая не найдется, то делать текущей первую. Но для этого придется сравнивать значения типа FLOAT, видимо используя какую-то точность сравнения. Или так и надо? :huh:
Других вариантов не придумала. У кого какие мысли есть по этому поводу? Спасибо.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ilyabvt
  опции профиля:
сообщение 3.2.2012, 23:51
Сообщение #2


Активный участник
***

Группа: Участник
Сообщений: 297
Регистрация: 23.6.2011
Пользователь №: 2765

Спасибо сказали: 45 раз(а)




Репутация:   3  


Цитата
3) Запоминать PARAM текущей строки, а при поступлении следующего массива искать в нем запись с запомненным PARAM и делать ее текущей? А если такая не найдется, то делать текущей первую. Но для этого придется сравнивать значения типа FLOAT, видимо используя какую-то точность сравнения. Или так и надо?

Да так и надо. Насчет точности не надо париться, если значение другое то оно и должно восприниматься как другое. Сравнивайте также как вы бы сравнивали целочисленные значения.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 4.2.2012, 21:22
Сообщение #3


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Цитата
Сравнивайте также как вы бы сравнивали целочисленные значения.
А это во всех СУБД срабатывает? Я работаю сейчас с Firebird.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ilyabvt
  опции профиля:
сообщение 4.2.2012, 22:46
Сообщение #4


Активный участник
***

Группа: Участник
Сообщений: 297
Регистрация: 23.6.2011
Пользователь №: 2765

Спасибо сказали: 45 раз(а)




Репутация:   3  


Цитата(Steklova Olga @ 5.2.2012, 0:22) *
Цитата
Сравнивайте также как вы бы сравнивали целочисленные значения.
А это во всех СУБД срабатывает? Я работаю сейчас с Firebird.

С Firebird не работал, но честно говоря не представляю, почему оно должно вдруг не сработать. Может вы меня не так поняли? Я не имел ввиду что нужно конвертировать в целочисленные, я имел ввиду что принцип их сравнения одинаковый
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 5.2.2012, 17:34
Сообщение #5


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Цитата
Я не имел ввиду что нужно конвертировать в целочисленные, я имел ввиду что принцип их сравнения одинаковый
Спасибо, я так и поняла.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 6.2.2012, 20:04
Сообщение #6


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Однако не все так тривиально...
1) Зачем-то же написана функция qFuzzyCompare:
пример
double d1, d2;
bool b1, b2;

d1 = 15000.0000000000;
d2 = 15000.0000000150;
b1 = (d1 == d2); //false
b2 = qFuzzyCompare(d1, d2); //true

d1 = 15000.0000000000;
d2 = 15000.0000000151;
b1 = (d1 == d2); //false
b2 = qFuzzyCompare(d1, d2); //false
Поиск записи с запомненным PARAM сделала с помощью qFuzzyCompare, учитывая обработку нулевых значений (help по этой функции).
2) Оказалось, что точности FLOAT для поля PARAM в таблице БД мне не хватает, заменила на DOUBLE PRECISION.
3) После этого не могла понять, почему
- из IBExpert получается добавить запись со значением PARAM, равным
15000.0000000151 (при этом в БД оказывается записанным
15000.0000000150994),
- а из моей программы при добавлении записи со значением PARAM, равным
15000.0000000151 в БД оказывается записанным
15000.
Дело было в том, что при формировании строки запроса на добавление записи в таблицу БД
я переводила значение в строку с помощью setNum, но использовала prec = 6 (по умолчанию).
Заменила s.setNum(d, 'f') на s.setNum(d, 'f', 10).

Проверила работу, указав в Qt::DisplayRole для PARAM формат
QString("%1").arg(value.toDouble(), 0, 'f', 10, QLatin1Char('0'));

4) Остался вопрос, какое "универсальное" (для любого поля типа DOUBLE PRECISION) значение prec лучше указать у меня в setNum при формировании запроса в общем случае, если таких параметров как PARAM у меня несколько, и я не знаю заранее их точный диапазон и точность, только знаю, что DOUBLE PRECISION подходит. prec = 15 что-ли? :rolleyes:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Tonal
  опции профиля:
сообщение 7.2.2012, 8:11
Сообщение #7


Активный участник
***

Группа: Участник
Сообщений: 452
Регистрация: 6.12.2007
Из: Новосибирск
Пользователь №: 34

Спасибо сказали: 69 раз(а)




Репутация:   17  


Цитата(Steklova Olga @ 7.2.2012, 0:04) *
Дело было в том, что при формировании строки запроса на добавление записи в таблицу БД
я переводила значение в строку с помощью setNum, но использовала prec = 6 (по умолчанию).
Заменила s.setNum(d, 'f') на s.setNum(d, 'f', 10).

Проверила работу, указав в Qt::DisplayRole для PARAM формат
QString("%1").arg(value.toDouble(), 0, 'f', 10, QLatin1Char('0'));

4) Остался вопрос, какое "универсальное" (для любого поля типа DOUBLE PRECISION) значение prec лучше указать у меня в setNum при формировании запроса в общем случае, если таких параметров как PARAM у меня несколько, и я не знаю заранее их точный диапазон и точность, только знаю, что DOUBLE PRECISION подходит. prec = 15 что-ли? :rolleyes:

Используй параметризированные запросы и биндинг переменных. Тогда тебе не нужно будет руками форматировать данные и натыкатся на точность. :)

Ну и почитай про числа с плавающей запятой - будешь лучше ориентироватся. :)

По поводу стартового вопроса было бы неплохо уточнить, зачем нужна вообще выделенная строка в таблице T2, если данные там постоянно меняются.
Какую она несёт функциональную нагрузку?
Ежели это понять, можно дальше думаьт про механизм обеспечения постоянства этого выделения.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 7.2.2012, 14:40
Сообщение #8


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


1)
Цитата
Используйте биндинг переменных
Понятно, как использовать биндинг, если надо добавить или обновить запись, а в запросе указать значения всех полей записи (конечно, кроме генератора).

А вот другой случай... И как Вы здесь прикрутите биндинг?
Например, есть таблица БД с полями ID (INTEGER, PK), PARAM (DOUBLE, необяз), FINT1 (INTEGER, необяз), FINT2 (INTEGER, необяз), FSTR (VARCHAR(20), необяз).
Для записи или обновления данных таблицы поступает структура, содержащая значения полей записи.
typedef struct {
    qint32 id;
    double param;
    qint32 fint1;
    qint32 fint2;
    QString str;
} tRec;
tRec Rec;
const qint32 null_qint32 = -1000;
const double null_double = -1000;
const double epsilon_double = 1.0;

Если поступает запись с новым id, то добавляем ее в таблицу.
Если поступает запись со старым id, то обновляем соотв. запись в таблице.
При формировании запросов из числа необязательных полей указываем только те, значения которых поступили в структуре, остальные значения полей должны остаться без изменения.
Используем следующие признаки того, что необязательные поля не поступили:
- для поля PARAM: param = null_double,
- для поля FINT1: fint1 = null_qint32,
- для поля FINT2: fint2 = null_qint32,
- для поля FSTR: str.isEmpty().

Сейчас я использую функцию, формирующую часть строки запроса для записи или обновления данных любой таблицы БД. Эта часть строки запроса имеет вид: "(<список наименований полей записи, поступивших в структуре>) VALUES (<список соотв. значений полей>)". Входным параметром функции является вектор. Элемент вектора - структура, содержащая информацию о поле таблицы, в том числе
    QString FieldName; //наименование поля таблицы
    QVariant FieldValue; //значение поля таблицы

//в самой функции
    if (vector[i].FieldValue.type() == QVariant::Double)
    {
        d = vector[i].FieldValue.toDouble();
        if (::qAbs(d - null_double) > epsilon_double)
        {
            s.setNum(d, 'f', 15); //15? здесь мне нужно универсальное значение prec
            sv += " " + s + ",";
            Flag_add = true;
        }
    }

2)
Цитата
По поводу стартового вопроса было бы неплохо уточнить, зачем нужна вообще выделенная строка в таблице T2, если данные там постоянно меняются.
Дело в том, что
- таблица предназначена для просмотра текущего массива оператором,
- для отображения таблицы на экране отведено не так много места, чтобы видеть сразу все записи, тем более, если их 200,
- не каждые 5 сек все значения массива меняются,
- Если оператор начнет скроллинг таблицы, а в это время, например, обновится массив только в одном значении (не в текущей строке), хочется, чтобы оператор спокойно остался на прежней текущей строке, а измененную строку он увидит, продолжив скроллинг.
Если не запоминать текущую строку, то невозможно будет спокойно просматривать массив, при каждом обновлении массива текущей будет становится первая строка.
Это будет даже в том случае, если данных разных массивов будут полностью совпадать, ведь я же удаляю старый массив и добавляю новый.

Сообщение отредактировал Steklova Olga - 7.2.2012, 14:57
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Tonal
  опции профиля:
сообщение 8.2.2012, 8:51
Сообщение #9


Активный участник
***

Группа: Участник
Сообщений: 452
Регистрация: 6.12.2007
Из: Новосибирск
Пользователь №: 34

Спасибо сказали: 69 раз(а)




Репутация:   17  


1)
Ты же вроде бы писала, что T2 ты очищаешь и вставляешь данные по новой. Т. е. в этом случае у тебя только 1 sql для удаления и 1 для вставки. Как использовать биндинг вроде очевидно :)

Но даже если рассматривать более общий случай, который ты описываешь, то можно использовать биндинг несколькими способами:
1. Генерить параметрический sql (без данных) для каждого случая.
2. Использовать всегда полный insert/update с биндингом а в триггерах разбираться какие реально поля изменяются
3. Вынести логику разборок с данными на сервер - в сохранённую процедурку.
Во всех 3х случаях кроме первого дополнительно к удобству работы с данными получаем ускорение на единственной генерации запроса клиентом и подготовке (препарации) запроса сервером. Да и в 1ом случае можно добавить систему кеширования позволяющую воспользоваться этими преимуществами. :)

2)
Почему тогда просто не привязываться к порядковому номеру и верхней видимой строке?
Других-то ориентиров у пользователя всё равно нету...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Steklova Olga
  опции профиля:
сообщение 8.2.2012, 12:14
Сообщение #10


Участник
**

Группа: Участник
Сообщений: 198
Регистрация: 27.9.2011
Из: Санкт-Петербург
Пользователь №: 2912

Спасибо сказали: 5 раз(а)




Репутация:   4  


Таблицы Т1 и Т2 - это один пример,
таблица БД с полями ID, PARAM, FINT1, FINT2, FSTR - это таблица Т3, другой пример.
В T1 записи только добавляются,
в T2 удаляются старые записи и добавляются новые,
в Т3 записи добавляются или обновляются в зависимости от поступившего ID
(UPDATE OR INSERT INTO T3 ... MATCHING (ID)).

Цитата(Tonal @ 8.2.2012, 8:51) *
Ты же вроде бы писала, что T2 ты очищаешь и вставляешь данные по новой. Т. е. в этом случае у тебя только 1 sql для удаления и 1 для вставки.
Да

Цитата(Tonal @ 8.2.2012, 8:51) *
Как использовать биндинг вроде очевидно
Так как в Т2 все поля обязательные, то для Т2 - да, очевидно.

Цитата(Steklova Olga @ 7.2.2012, 14:40) *
Если оператор начнет скроллинг таблицы, а в это время, например, обновится массив только в одном значении (не в текущей строке), хочется, чтобы оператор спокойно остался на прежней текущей строке, а измененную строку он увидит, продолжив скроллинг.
Если не запоминать текущую строку, то невозможно будет спокойно просматривать массив, при каждом обновлении массива текущей будет становится первая строка.
Это будет даже в том случае, если данных разных массивов будут полностью совпадать, ведь я же удаляю старый массив и добавляю новый.
Здесь я говорю о Т2. А под словом "обновится" я подразумеваю не то, что я делаю таблице UPDATE, а то, что меняются данные поступающего массива, например.
Поступает 1-й раз массив со значениями PARAM (1.23, 2.34, 300.45, 445.00),
оператор начинает его просмотр,
делает текущей запись со значением 300.45,
поступает 2-й раз массив со значениями PARAM (1.23, 2.34, 300.45, 1888.00),
<здесь я перерисовываю таблицу, но хочу, чтобы текущей осталась запись со значением 300.45>,
поступает 3-й раз массив со значениями PARAM (1.23, 2.34, 300.45, 1888.00, 2001.45),
<здесь я перерисовываю таблицу, но хочу, чтобы текущей осталась запись со значением 300.45>.

Цитата(Tonal @ 8.2.2012, 8:51) *
Почему тогда просто не привязываться к порядковому номеру и верхней видимой строке?
Других-то ориентиров у пользователя всё равно нету...
В соотв. с выше написанным, мне надо привязываться не к ID, а к PARAM, ориентир - это PARAM.

Но я-то хочу во всех случаях (для Т1, Т2, Т3 и любых других моих таблиц, в том числе с любым количеством необяз. полей) использовать одну функцию формирования запроса.
Поэтому я и пишу s.setNum(d, 'f', 15).

Читаю дальше Ваши предложения...
Цитата(Tonal @ 8.2.2012, 8:51) *
Но даже если рассматривать более общий случай, который ты описываешь, то можно использовать биндинг несколькими способами:
1. Генерить параметрический sql (без данных) для каждого случая.
Если я Вас правильно поняла, то в этом случае для Т3, в которой четыре необяз. поля, придется писать 16 параметр. sql (все комбинации).

Цитата(Tonal @ 8.2.2012, 8:51) *
2. Использовать всегда полный insert/update с биндингом а в триггерах разбираться какие реально поля изменяются
Я пока не настолько сильна в триггерах, чтобы такое написать. Пока что, использую триггеры только для генераторов.

Цитата(Tonal @ 8.2.2012, 8:51) *
3. Вынести логику разборок с данными на сервер - в сохранённую процедурку.
Очень хорошо, а что будет в этой хранимой процедуре? :scratch_one-s_head: Не могли бы Вы, Tonal, если не жалко, набросать код для случая обновления данных в таблице Т3?

Цитата(Tonal @ 8.2.2012, 8:51) *
Да и в 1ом случае можно добавить систему кеширования позволяющую воспользоваться этими преимуществами.
А эти слова для меня вообще пока как китайская грамота. :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 24.4.2024, 14:46