SnowConvert: Teradata¶
数值数据运算¶
计算精度¶
Teradata 与 Snowflake 处理计算的方式各有不同:
Teradata 根据数据类型,在完成每个计算步骤之后对数字进行四舍五入:
对于十进制类型,它会保持更高的精度
对于 NUMBER 类型,它会保持全精度
Snowflake 使用 NUMBER 数据类型存储所有数字,并在整个计算过程中保持全精度。这可能会导致结果不同于 Teradata,尤其是在使用十进制、整数或浮点类型时。
这种行为差异在代码转换期间不会调整,因为开发者通常并无作出此更改的意图。
Teradata: SELECT (1.00/28) * 15.00 /* 返回 0.60 */
Snowflake 会将除法运算 (1.00/28) * 15.00 的结果舍入到小数点后两位:SELECT (1.00/28) * 15.00 = 0.535710 = 0.54
整数与整数之间的除法¶
将两个整数值相除时,Teradata 会执行截断(向下取整),而 Snowflake 则执行舍入。为了在迁移期间保持一致的行为,自动代码转换会在此类情况下自动添加 TRUNC 语句。
Teradata: SELECT (5/3) = 1 /* 整数除法向下舍入,因此返回 1 */
Snowflake:当 5 除以 3 时,结果为 1.6666666,舍入的结果为 2
Snowflake 中截断的除法:SELECT TRUNC(5/3) 返回 1
Banker 式舍入¶
Teradata 通过 ROUNDHALFWAYMAGUP 参数提供 Banker 式舍入功能,而 Snowflake 仅使用标准舍入方法。
SQL |
Teradata |
Snowflake |
---|---|---|
CAST( 1.05 AS DECIMAL(9,1)) |
1.0 |
1.1 |
CAST( 1.15 AS DECIMAL(9,1)) |
1.2 |
1.2 |
CAST( 1.25 AS DECIMAL(9,1)) |
1.2 |
1.3 |
CAST( 1.35 AS DECIMAL(9,1)) |
1.4 |
1.4 |
CAST( 1.45 AS DECIMAL(9,1)) |
1.4 |
1.5 |
CAST( 1.55 AS DECIMAL(9,1)) |
1.6 |
1.6 |
CAST( 1.65 AS DECIMAL(9,1)) |
1.6 |
1.7 |
CAST( 1.75 AS DECIMAL(9,1)) |
1.8 |
1.8 |
CAST( 1.85 AS DECIMAL(9,1)) |
1.8 |
1.9 |
CAST( 1.95 AS DECIMAL(9,1)) |
2.0 |
2.0 |
十进制到整数的转换¶
Teradata 与 Snowflake 处理十进制值的方式各有不同。Teradata 会截断十进制值,而 Snowflake 会将其舍入到最接近的整数。为了保持与 Teradata 行为的一致性,转换过程会自动添加 TRUNC 语句。
SQL |
Teradata |
Snowflake |
---|---|---|
CAST( 1.0 AS INTEGER) |
1 |
1 |
CAST( 1.1 AS INTEGER) |
1 |
1 |
CAST( 1.2 AS INTEGER) |
1 |
1 |
CAST( 1.3 AS INTEGER) |
1 |
1 |
CAST( 1.4 AS INTEGER) |
1 |
1 |
CAST( 1.5 AS INTEGER) |
1 |
2 |
CAST( 1.6 AS INTEGER) |
1 |
2 |
CAST( 1.7 AS INTEGER) |
1 |
2 |
CAST( 1.8 AS INTEGER) |
1 |
2 |
CAST( 1.9 AS INTEGER) |
1 |
2 |
不带精度/小数位数的数字¶
如果在未指定小数位数或精度的情况下定义 Teradata NUMBER 列,它依然可以存储小数,小数位数可在 0 至 38 之间变化,只要总精度保持在 38 位以内即可。但 Snowflake 要求 NUMBER 列使用固定的小数位数和精度值。下面的示例展示了如何使用这种灵活格式在 Teradata 表中定义数字:
CREATE MULTISET TABLE DATABASEXYZ.TABLE_NUMS
(NUM_COL1 NUMBER(*),
NUM_COL2 NUMBER,
NUM_COL3 NUMBER(38,*));
下表展示了两个超过 Snowflake 列大小限制的值的示例。这些值可能出现在先前显示的任何 Teradata 列中。
值 1:123,345,678,901,234,567,891,012.0123456789
值 2:123.12345678901234567890
这些数值需要 NUMBER(42, 20) 数据类型,这超出了 Snowflake 的最大精度限制 38。Snowflake 目前正在努力实现灵活的精度和小数位数功能。
SQL DML 语句 INSERT 操作中的截断¶
在执行插入操作期间,Teradata 会自动截断超过既定字段长度的字符串值。虽然 SnowConvert 在转换期间会保持相同的字段长度(例如,VARCHAR(20) 仍然是 VARCHAR(20)),但 Snowflake 不会自动截断过长的字符串。如果您的数据引入过程依赖于自动截断,则需要通过添加 LEFT() 函数来手动对其进行修改。出于对整个代码库潜在影响的考虑,SnowConvert 有意未添加自动截断功能。
浮点默认问题示例:¶
/* <sc-table> TABLE DUMMY.EXAMPLE </sc-table> */
/**** WARNING: SET TABLE FUNCTIONALITY NOT SUPPORTED ****/
CREATE TABLE DUMMY.PUBLIC.EXAMPLE (
LOGTYPE INTEGER,
OPERSEQ INTEGER DEFAULT 0,
RUNTIME FLOAT /**** ERROR: DEFAULT CURRENT_TIME NOT VALID FOR DATA TYPE ****/
);
浮点数据聚合¶
浮点数是对十进制值的近似表示。由于这些近似值,使用浮点数据类型执行计算和聚合时,不同的数据库系统产生的结果可能略有不同。之所以存在这种差异,是因为每个数据库系统都以自己的方式处理浮点算术和舍入。
其他注意事项¶
联接消除¶
Snowflake 完全按照 SQL 查询的编写方式执行这些查询,包括所有指定的联接,无论其是否影响最终结果。不同于 Snowflake,Teradata 可以使用表结构中定义的主键和外键关系,自动删除不必要的联接。Teradata 中的这项功能主要有助于防止编写不当的查询,通常只有在代码专门为使用此功能而编写时,这才会成为问题。如果您的现有代码旨在利用 Teradata 的联接消除功能,则自动代码转换工具无法解决此限制条件。在此类情况下,您可能需要重新设计解决方案的某些部分。
使用带有 max() 和 order by 的窗口函数
Teradata 行为和默认设置:¶
默认设置:当存在 ORDER BY 子句但未指定 ROWS 或 ROWS BETWEEN 子句时,Teradata SQL 窗口聚合函数会自动使用 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。
Snowflake 行为和默认设置:¶
默认设置:如果您使用带有 ORDER BY 子句的窗口聚合函数,但未指定 ROWS 或 ROWS BETWEEN,Snowflake 会自动应用 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 作为窗口框架。
示例:
以下是名为 TEST_WIN 的示例表,其中显示了各部门的员工薪资数据。
DEPT_NM | DEPT_NO | EMP_NO | SALARY |
---|---|---|---|
SALES | 10 | 11 | 5000 |
SALES | 10 | 12 | 6000 |
HR | 20 | 21 | 1000 |
HR | 20 | 22 | 2000 |
PS | 30 | 31 | 7000 |
PS | 30 | 32 | 9000 |
以下代码在 Teradata 中执行时,会按部门分组计算所有员工中最高的工资。
SELECT DEPT_NM, SALARY ,DEPT_NO,
MAX(SALARY) OVER ( ORDER BY DEPT_NO ) AS MAX_DEPT_SALARY
FROM TEST_WIN;
DEPT_NM | SALARY | DEPT_NO | MAX_DEPT_SALARY |
---|---|---|---|
SALES | 6000 | 10 | 9000 |
SALES | 5000 | 10 | 9000 |
HR | 2000 | 20 | 9000 |
HR | 1000 | 20 | 9000 |
PS | 7000 | 30 | 9000 |
PS | 9000 | 30 | 9000 |
使用 Snowflake-SnowConvert 执行转换后的代码时,您可能会注意到结果有所不同(突出显示的值)。这些差异符合预期,与 Snowflake 的默认设置一致。
SELECT DEPT_NM, SALARY ,DEPT_NO,
MAX(SALARY) OVER ( ORDER BY DEPT_NO ) AS MAX_DEPT_SALARY
FROM TEST_WIN;
DEPT_NM | SALARY | DEPT_NO | MAX_DEPT_SALARY |
---|---|---|---|
SALES | 5000 | 10 | 6000 |
SALES | 6000 | 10 | 6000 |
HR | 1000 | 20 | 6000 |
HR | 2000 | 20 | 6000 |
PS | 7000 | 30 | 9000 |
PS | 9000 | 30 | 9000 |
要在 Teradata 中获得相同的结果,必须指定 ROWS/RANGE 值,如以下代码所示。
SELECT DEPT_NM, SALARY ,DEPT_NO,
MAX(SALARY) OVER ( ORDER BY DEPT_NO RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS MAX_DEPT_SALARY
FROM TEST WIN;
DEPT_NM | SALARY | DEPT_NO | MAX_DEPT_SALARY |
---|---|---|---|
SALES | 5000 | 10 | 9000 |
SALES | 6000 | 10 | 9000 |
HR | 1000 | 20 | 9000 |
HR | 2000 | 20 | 9000 |
PS | 7000 | 30 | 9000 |
PS | 9000 | 30 | 9000 |
RANGE/ROWS 子句明确定义了行的排序方式。通过完全删除 ORDER BY 子句,即可获得类似的结果。
引用¶
Snowflake:https://docs.snowflake.cn/en/sql-reference/functions-analytic.html Teradata:https://docs.teradata.com/r/756LNiPSFdY~4JcCCcR5Cw/dIV_fAtkK3UeUIQ5_uucQw (https://docs.teradata.com/r/756LNiPSFdY~4JcCCcR5Cw/dIV_fAtkK3UeUIQ5_uucQw)