【问题标题】:When is type casting SQL columns required?什么时候需要类型转换 SQL 列?
【发布时间】:2019-03-01 01:48:32
【问题描述】:

我执行了第一个查询,但没有得到预期的结果。然后我意识到1 slope 被解释为整数,因此t.slope*pchp.sign*p.slope slope, t.intercept+t.slope*pchp.sign*p.intercept intercept 中的t.slope 也充当整数。

然后我重复了查询,但这次将slope 和intercept 都转换为小数,并获得了正确的结果。

然后我又重复了第二次查询,但只对值不为零但不是intercept的slope进行了一次转换,也得到了正确的结果。

这引出了我的问题。什么时候需要类型转换 SQL 列?

MariaDB [testing]> WITH RECURSIVE t AS (
    -> SELECT id, id pointsId, type, 0 value, 0 prevValue, 1 slope, 0 intercept
    -> FROM points
    -> WHERE id IN (406, 428)
    -> UNION ALL
    -> SELECT t.id, pchp.pointsId, p.type, p.value, p.prevValue, t.slope*pchp.sign*p.slope slope, t.intercept+t.slope*pchp.sign*p.intercept intercept
    -> FROM t
    -> INNER JOIN points_custom_has_points pchp ON pchp.pointsCustomId=t.pointsId
    -> INNER JOIN points p ON p.id=pchp.pointsId
    -> )
    -> SELECT id, SUM(slope*value+intercept) value, SUM(slope*prevValue+intercept) prevValue FROM t WHERE type='real' GROUP BY id;
+-----+--------+-----------+
| id  | value  | prevValue |
+-----+--------+-----------+
| 406 |      0 |         0 |
| 428 | 123702 |    123702 |
+-----+--------+-----------+
2 rows in set (0.00 sec)

MariaDB [testing]> WITH RECURSIVE t AS (
    -> SELECT id, id pointsId, type, 0 value, 0 prevValue, CAST(1 AS DECIMAL(12,4)) slope, CAST(0 AS DECIMAL(12,4)) intercept
    -> FROM points
    -> WHERE id IN (406, 428)
    -> UNION ALL
    -> SELECT t.id, pchp.pointsId, p.type, p.value, p.prevValue, t.slope*pchp.sign*p.slope slope, t.intercept+t.slope*pchp.sign*p.intercept intercept
    -> FROM t
    -> INNER JOIN points_custom_has_points pchp ON pchp.pointsCustomId=t.pointsId
    -> INNER JOIN points p ON p.id=pchp.pointsId
    -> )
    -> SELECT id, SUM(slope*value+intercept) value, SUM(slope*prevValue+intercept) prevValue FROM t WHERE type='real' GROUP BY id;
+-----+-------------+-------------+
| id  | value       | prevValue   |
+-----+-------------+-------------+
| 406 |  49480.8000 |  49480.8000 |
| 428 | 123702.0000 | 123702.0000 |
+-----+-------------+-------------+
2 rows in set (0.00 sec)

MariaDB [testing]> WITH RECURSIVE t AS (
    -> SELECT id, id pointsId, type, 0 value, 0 prevValue, CAST(1 AS DECIMAL(12,4)) slope, 0 intercept
    -> FROM points
    -> WHERE id IN (406, 428)
    -> UNION ALL
    -> SELECT t.id, pchp.pointsId, p.type, p.value, p.prevValue, t.slope*pchp.sign*p.slope slope, t.intercept+t.slope*pchp.sign*p.intercept intercept
    -> FROM t
    -> INNER JOIN points_custom_has_points pchp ON pchp.pointsCustomId=t.pointsId
    -> INNER JOIN points p ON p.id=pchp.pointsId
    -> )
    -> SELECT id, SUM(slope*value+intercept) value, SUM(slope*prevValue+intercept) prevValue FROM t WHERE type='real' GROUP BY id;
+-----+-------------+-------------+
| id  | value       | prevValue   |
+-----+-------------+-------------+
| 406 |  49480.8000 |  49480.8000 |
| 428 | 123702.0000 | 123702.0000 |
+-----+-------------+-------------+
2 rows in set (0.00 sec)

MariaDB [testing]>

表定义如下:

MariaDB [testing]> explain points;
+----------------+-------------+------+-----+---------+----------------+
| Field          | Type        | Null | Key | Default | Extra          |
+----------------+-------------+------+-----+---------+----------------+
| id             | int(11)     | NO   | PRI | NULL    | auto_increment |
| idPublic       | int(11)     | NO   | MUL | 0       |                |
| accountsId     | int(11)     | NO   | MUL | NULL    |                |
| name           | varchar(45) | NO   | MUL | NULL    |                |
| value          | float       | YES  |     | NULL    |                |
| prevValue      | float       | YES  |     | NULL    |                |
| units          | varchar(45) | YES  |     | NULL    |                |
| type           | char(8)     | NO   | MUL | NULL    |                |
| slope          | float       | NO   |     | 1       |                |
| intercept      | float       | NO   |     | 0       |                |
| tsValueUpdated | datetime    | YES  |     | NULL    |                |
| sourceTypeId   | tinyint(4)  | YES  | MUL | NULL    |                |
+----------------+-------------+------+-----+---------+----------------+
12 rows in set (0.00 sec)

MariaDB [testing]> explain points_custom_has_points;
+----------------+------------+------+-----+---------+-------+
| Field          | Type       | Null | Key | Default | Extra |
+----------------+------------+------+-----+---------+-------+
| pointsCustomId | int(11)    | NO   | PRI | NULL    |       |
| pointsId       | int(11)    | NO   | PRI | NULL    |       |
| sign           | tinyint(4) | NO   | MUL | 1       |       |
+----------------+------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

MariaDB [testing]>

【问题讨论】:

  • 很高兴看到一些(简洁的)表定义。一般来说,你应该总是在必要时进行强制转换,事实上许多其他数据库在这方面比 MySQL/MariaDB 严格得多。
  • @TimBiegeleisen 添加了定义。是的,我认为我应该总是在必要时这样做:) 但是什么时候有必要呢?您关于其他数据库更严格的评论使我相信我应该始终这样做,除非列数据类型由表定义规定,并且我也应该将 0 类型转换为整数,即使它不这样做也可以工作。
  • 嗯,sign tinyint(4) 会引起问题吗?

标签: mysql casting mariadb


【解决方案1】:

将CAST(1 AS DECIMAL(12,4)) slope 更改为1.0 slope。如果可行,那么这里是解释:

UNION 中的第一个 SELECT 确定每列的数据类型。所以,简单地说1 会将斜率设置为某种整数(我认为BIGINT)。

您可能对其他列有类似的问题。

我怀疑由于WITH,您无法在UNION 中交换SELECTs。但这可能是另一回事。 (如果您尝试过,请报告。)

【讨论】:

    猜你喜欢
    • 2017-12-15
    • 2018-12-10
    • 2015-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    • 2022-11-09
    • 1970-01-01
    相关资源
    最近更新 更多