Russian Qt Forum
Июнь 25, 2018, 11:07 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Извлечение float из таблицы  (Прочитано 494 раз)
Yegor
Самовар
**
Offline Offline

Сообщений: 176


Просмотр профиля
« : Май 18, 2018, 17:24 »

Всем здравствуйте!

Работаю с OC Linux Ubuntu, Qt 5.7.1, MySQL v 5.7.22

Извлекаю запросом (QSqlQuery) данные (float) таблицы и конвертирую результат ( QSqlQuery.record().value("MyVal).toFloat() )

Если чило число в базе не имеет значения после запятой ( например, 12.0 ), то результат извлекается.
А если число в базе со значением после запятой ( например, 12.2 ), то результат не извлекается (QVariant::invalid).

Подскажите, пожалуйста, что нужно знать еще по поводу извлечения float чисел из базы. Локаль? Что нибудь еще?

Спасибо!
« Последнее редактирование: Май 21, 2018, 11:56 от Yegor » Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 3914



Просмотр профиля
« Ответ #1 : Май 18, 2018, 17:29 »

Локаль.Из базы может возвращаться значение с разделителем запятая, а в локале прописана точка. Или наоборот.
Записан
Yegor
Самовар
**
Offline Offline

Сообщений: 176


Просмотр профиля
« Ответ #2 : Май 18, 2018, 17:52 »

А как локаль настраивать? Ведь настройки локали есть и для OC и для приложения и для MySQL.
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 3914



Просмотр профиля
« Ответ #3 : Май 18, 2018, 18:31 »

А как локаль настраивать? Ведь настройки локали есть и для OC и для приложения и для MySQL.
Класс QLocale умеет необходимые преобразования.
Записан
Yegor
Самовар
**
Offline Offline

Сообщений: 176


Просмотр профиля
« Ответ #4 : Май 18, 2018, 21:26 »

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

Создаю простую базу для проверки.

Код
SQL
CREATE DATABASE Decimals;
USE Decimals;
 
CREATE TABLE MyFloats
(
   id integer UNSIGNED NOT NULL auto increment PRIMARY KEY,
   my_float float
);
 
INSERT INTO MyFloats (my_float) VALUES (1), (1.01), (0.02);
SELECT * FROM MyFloats;
+----+----------+
| id | my_float |
+----+----------+
|  1 |        1 |
|  2 |     1.01 |
|  3 |     0.02 |
+----+----------+
 

Далее  минимально компилируемый проект для проверки.

Код
C++ (Qt)
#include <QtDebug>
#include <QtSql>
#include <QtCore/QLocale>
#include <QCoreApplication>
 
int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
 
   try
   {
 
       // Test the locale 1.
       /*QLocale defLocale ( QLocale::Language::Russian, QLocale::Country::Ukraine );
       QLocale::setDefault ( defLocale );
       qInfo() << "Def decimal point:" << defLocale.decimalPoint();*/

 
       // Test the locale 2.
       QLocale generalC ( QLocale::Language::C );
       QLocale::setDefault( generalC );
       qInfo() << "General decimal point:" << generalC.decimalPoint();
 
       QSqlDatabase db = QSqlDatabase::addDatabase ( "QMYSQL" );
       db.setDatabaseName("Decimals");
       db.setUserName("MyUser");
       db.setPassword("MyPass");
       if ( !db.open() )
           throw QString("cannot open db: %1").arg( db.lastError().text() );
 
       // Prepare.
       QSqlQuery query;
       if ( !query.prepare (
                " SELECT "
                "  my_float "
                " FROM "
                "  MyFloats "
                ) )
           throw QString("cannot prepare query: %1").arg(query.lastError().text());
 
       // Exec.
       if ( !query.exec() )
           throw QString("cannot exec query: %1").arg(query.lastError().text());
 
       // Extract.
       qInfo() <<"Result:";
       while ( query.next() )
       {
           qInfo() << query.record().fieldName(0)
                   << query.record().value(0).toString();
       }
 
       db.close();
 
 
       // Casting from QByteArray.
       qInfo() << "Cast from byte array:" << QByteArray("1.002").toFloat();
 
       return 0;
   }
   catch ( QString& strErr )
   {
       qCritical() << "Error:" << strErr;
   }
   catch (...)
   {
       qCritical() << "Unknown error.";
   }
 
   return -1;
}
 

И вывод приложения:
Код:
General decimal point: '.'
Result:
"my_float" "1"
"my_float" ""
"my_float" ""
Cast from byte array: 1.002

То есть видно, что число без дробной части извлеклось, а числа с дробными значениями - нет.

Все ли я правильно сделал? Может еще что не учел? Может указывать дополнительные опции при соединении - QSqlDatabase::setConnectOptions(const QString &options = QString()) ? (Там я не нашел что либо касательно форматов чисел).
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 3914



Просмотр профиля
« Ответ #5 : Май 18, 2018, 21:42 »

А что будет если попробовать установить локаль с разделителем "," и если не устанавливать локаль вообще?
И попробуйте получать значения без формирования QSqlRecord, т.е. так query.value( 0 )
Записан
Yegor
Самовар
**
Offline Offline

Сообщений: 176


Просмотр профиля
« Ответ #6 : Май 19, 2018, 12:29 »

Делаю вывод типа qInfo() << query.value(0)

1) Делаю локаль с разделителем , (раскоментирую в исходниках первый блок, комментирую второй). Выводит:
Код:
Decimal point: ','
Result:
QVariant(double, 1)
QVariant(Invalid)
QVariant(Invalid)

2) Делаю локаль с разделителем . (раскоментирую в исходниках второй блок, комментирую первый). Выводит:
Код:
Decimal point: '.'
Result:
QVariant(double, 1)
QVariant(Invalid)
QVariant(Invalid)

3) Вообще не устанавливаю локаль (коментирую 2 блока)
Вывод:
Код:
Decimal point: '.'
Result:
QVariant(double, 1)
QVariant(Invalid)
QVariant(Invalid)

То есть не зависит от разделителя.

Далее я экспериментировал со структурой таблицы в mysql. Сделал тип столбца не float, a float (6,2).
Код:
+----------+------------------+------+-----+---------+----------------+
| Field    | Type             | Null | Key | Default | Extra          |
+----------+------------------+------+-----+---------+----------------+
| id       | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| my_float | float(6,2)       | YES  |     | NULL    |                |
+----------+------------------+------+-----+---------+----------------+

И вывод программы в таком случае (с разными комбинациями локалей) одинаковый -
Код:
Result:
QVariant(Invalid)
QVariant(Invalid)
QVariant(Invalid)

То есть вообще числа не распознаются.

Далее я экспериментировал, изменил структуру таблицы, вместо float сделал varchar(10).
Код:
+----------+------------------+------+-----+---------+----------------+
| Field    | Type             | Null | Key | Default | Extra          |
+----------+------------------+------+-----+---------+----------------+
| id       | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| my_float | varchar(10)      | YES  |     | NULL    |                |
+----------+------------------+------+-----+---------+----------------+

В таком случае все считывается нормально. Не зависимо от локали.
Если выводить с помощью qInfo() << record(0), то вывод:
Result:
Код:
QVariant(QString, "1.00")
QVariant(QString, "1.01")
QVariant(QString, "0.02")

А если через QRecord и конвертировать (во float)
qInfo() << query.record().value(0).toFloat()
Result:
Код:
1
1.01
0.02

Как вы думаете, почему не работает вывод, если тип столбце таблицы - float (да и double тоже)?
И хороршая ли практика, если столбец вместо float делать varchar?
Записан
Yegor
Самовар
**
Offline Offline

Сообщений: 176


Просмотр профиля
« Ответ #7 : Май 21, 2018, 11:55 »

Проверил этот же пример и эту же базу данных на других операционных системах (Windows7, FreeBSD). И все работает нормально (правильно извлекает float), не зависимо от локали. Значит, проблема не в программе, а в ОС Ubuntu или Qt. А в чем именно, не определил. Но не в программе. Проблема решена.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  

Страница сгенерирована за 0.103 секунд. Запросов: 22.