Laravel 5.0 PDO从MySQL查询浮点数会产生不准确的结果

时间:2016-01-21 11:16:37

标签: php mysql pdo laravel-5

为了表明我的问题我做了两个功能。第一个向Laravel请求PDO实例并查询数据库。在第二个我自己实现一个新的。 Laravel的第一个结果不准确。第二个给出正确的结果。

表格的定义是这样的:

CREATE TABLE IF NOT EXISTS `event` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `level` float DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

这是第一个功能:

public function testpdo1() {
    $pdo = DB::connection('myconnection')->getPdo();        
    $query = "SELECT level FROM event LIMIT 4";
    $result = $pdo->query($query);
    foreach ($result as $row) {
        print $row[0] ."\n";
    }
}

这给出了这些结果:

102.09999847412
97.900001525879
95.300003051758
94.099998474121

这是第二个功能:

public function testpdo2() {
    $pdo = new PDO('dsn', 'user', 'pass');
    $query = "SELECT level FROM event LIMIT 4";
    $result = $pdo->query($query);
    foreach ($result as $row) {
        print $row[0] ."\n";
    }
}

这给出了这些结果:

102.1
97.9
95.3
94.1

最后一个是正确的结果。

有没有办法让Laravel在第二个函数中表现得像?

我认为差异在于PDO设置。我尝试设置PDO :: ATTR_STRINGIFY_FETCHES但无济于事。我也尝试在第二个函数中查看是否可以使第二个出错。但它没有用。

也许我设置这样的属性有问题。使用laravel(函数1)我尝试将它/config/database.php设置为我的连接选项:

'connections' => [

    'myconnection' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge'),
        'username'  => env('DB_USERNAME', 'forge'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
        'options'   => array (
            PDO::ATTR_STRINGIFY_FETCHES => true,
        ),
    ],
....

使用第二个功能我用

尝试了
$pdo = new PDO('dsn', 'user', 'pass', [PDO::ATTR_STRINGIFY_FETCHES => true]);

$pdo->setAttribute ( PDO::ATTR_STRINGIFY_FETCHES , true );
在实例化之后

,具有真假值。它似乎没有任何区别......

这个问题接近我的问题:PHP PDO query returns inaccurate value for FLOAT fields 。但由于我的第二个功能给出了正确的答案,因此似乎可以得到准确的答案。

@Ragu Swaminathan建议第二个函数给出舍入值。需要明确的是:这些是数据库中的值。

mysql> select level from event LIMIT 4;
+-------+
| level |
+-------+
| 102.1 |
|  97.9 |
|  95.3 |
|  94.1 |
+-------+
4 rows in set (0.00 sec)

当我在函数1的查询中使用舍入时,值变为与函数2中的值相同。这是一种可能的解决方法,但我希望有更好的解决方案。

1 个答案:

答案 0 :(得分:0)

这两个函数表现不同的原因确实在PDO设置中。 参数PDO :: ATTR_EMULATE_PREPARES的默认值为true。 Laravel将此参数设置为false。

所以@Ragu Swaminathan是对的。第二个函数给出了舍入值。和mysql_client,phpmyadmin,perl等一样。

我做了一些我希望分享的第二个功能的测试。我稍微改了一下。

public function testpdo2() {
    $pdo = new PDO('dsn', 'user', 'pass');
    $query = "SELECT level FROM `test`";
    $result = $pdo->query($query);
    foreach ($result as $row) {
        print gettype($row[0]).' : '.$row[0]."<br>";
    }
}

结果是

string : 102.1
string : 97.9
string : 95.3
string : 94.1

所以我得到了字符串

当我在实施PDO后放入这一行

$pdo->setAttribute ( PDO::ATTR_EMULATE_PREPARES, false );

结果是

double : 102.09999847412
double : 97.900001525879
double : 95.300003051758
double : 94.099998474121

当我也(!)添加这一行

$pdo->setAttribute ( PDO::ATTR_STRINGIFY_FETCHES , true );

结果是

string : 102.09999847412
string : 97.900001525879
string : 95.300003051758
string : 94.099998474121

这就是为什么这似乎没有帮助

我的最后一次测试是将值102.09999847412插入表中。 &#34;正常&#34;回答为102.1

结论是:花车不值得信任。 但我们已经知道了; - )