просмотр таблицы с меняющимися данными, запоминание и выделение тек строки |
Здравствуйте, гость ( Вход | Регистрация )
просмотр таблицы с меняющимися данными, запоминание и выделение тек строки |
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, видимо используя какую-то точность сравнения. Или так и надо? Других вариантов не придумала. У кого какие мысли есть по этому поводу? Спасибо. |
|
|
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 |
Цитата Сравнивайте также как вы бы сравнивали целочисленные значения. А это во всех СУБД срабатывает? Я работаю сейчас с 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: пример
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 формат
4) Остался вопрос, какое "универсальное" (для любого поля типа DOUBLE PRECISION) значение prec лучше указать у меня в setNum при формировании запроса в общем случае, если таких параметров как PARAM у меня несколько, и я не знаю заранее их точный диапазон и точность, только знаю, что DOUBLE PRECISION подходит. prec = 15 что-ли? |
|
|
Tonal |
7.2.2012, 8:11
Сообщение
#7
|
Активный участник Группа: Участник Сообщений: 452 Регистрация: 6.12.2007 Из: Новосибирск Пользователь №: 34 Спасибо сказали: 69 раз(а) Репутация: 17 |
Дело было в том, что при формировании строки запроса на добавление записи в таблицу БД я переводила значение в строку с помощью setNum, но использовала prec = 6 (по умолчанию). Заменила s.setNum(d, 'f') на s.setNum(d, 'f', 10). Проверила работу, указав в Qt::DisplayRole для PARAM формат
4) Остался вопрос, какое "универсальное" (для любого поля типа DOUBLE PRECISION) значение prec лучше указать у меня в setNum при формировании запроса в общем случае, если таких параметров как PARAM у меня несколько, и я не знаю заранее их точный диапазон и точность, только знаю, что DOUBLE PRECISION подходит. prec = 15 что-ли? Используй параметризированные запросы и биндинг переменных. Тогда тебе не нужно будет руками форматировать данные и натыкатся на точность. Ну и почитай про числа с плавающей запятой - будешь лучше ориентироватся. По поводу стартового вопроса было бы неплохо уточнить, зачем нужна вообще выделенная строка в таблице 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), необяз). Для записи или обновления данных таблицы поступает структура, содержащая значения полей записи.
Если поступает запись с новым id, то добавляем ее в таблицу. Если поступает запись со старым id, то обновляем соотв. запись в таблице. При формировании запросов из числа необязательных полей указываем только те, значения которых поступили в структуре, остальные значения полей должны остаться без изменения. Используем следующие признаки того, что необязательные поля не поступили: - для поля PARAM: param = null_double, - для поля FINT1: fint1 = null_qint32, - для поля FINT2: fint2 = null_qint32, - для поля FSTR: str.isEmpty(). Сейчас я использую функцию, формирующую часть строки запроса для записи или обновления данных любой таблицы БД. Эта часть строки запроса имеет вид: "(<список наименований полей записи, поступивших в структуре>) VALUES (<список соотв. значений полей>)". Входным параметром функции является вектор. Элемент вектора - структура, содержащая информацию о поле таблицы, в том числе
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)). Ты же вроде бы писала, что T2 ты очищаешь и вставляешь данные по новой. Т. е. в этом случае у тебя только 1 sql для удаления и 1 для вставки. ДаКак использовать биндинг вроде очевидно Так как в Т2 все поля обязательные, то для Т2 - да, очевидно.Если оператор начнет скроллинг таблицы, а в это время, например, обновится массив только в одном значении (не в текущей строке), хочется, чтобы оператор спокойно остался на прежней текущей строке, а измененную строку он увидит, продолжив скроллинг. Здесь я говорю о Т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>. Почему тогда просто не привязываться к порядковому номеру и верхней видимой строке? В соотв. с выше написанным, мне надо привязываться не к ID, а к PARAM, ориентир - это PARAM.Других-то ориентиров у пользователя всё равно нету... Но я-то хочу во всех случаях (для Т1, Т2, Т3 и любых других моих таблиц, в том числе с любым количеством необяз. полей) использовать одну функцию формирования запроса. Поэтому я и пишу s.setNum(d, 'f', 15). Читаю дальше Ваши предложения... Но даже если рассматривать более общий случай, который ты описываешь, то можно использовать биндинг несколькими способами: Если я Вас правильно поняла, то в этом случае для Т3, в которой четыре необяз. поля, придется писать 16 параметр. sql (все комбинации).1. Генерить параметрический sql (без данных) для каждого случая. 2. Использовать всегда полный insert/update с биндингом а в триггерах разбираться какие реально поля изменяются Я пока не настолько сильна в триггерах, чтобы такое написать. Пока что, использую триггеры только для генераторов.3. Вынести логику разборок с данными на сервер - в сохранённую процедурку. Очень хорошо, а что будет в этой хранимой процедуре? Не могли бы Вы, Tonal, если не жалко, набросать код для случая обновления данных в таблице Т3? Да и в 1ом случае можно добавить систему кеширования позволяющую воспользоваться этими преимуществами. А эти слова для меня вообще пока как китайская грамота.
|
|
|
Текстовая версия | Сейчас: 25.11.2024, 16:37 |