Amazon Redshift - 横向列别名参考
Posted
技术标签:
【中文标题】Amazon Redshift - 横向列别名参考【英文标题】:Amazon Redshift - lateral column alias reference 【发布时间】:2019-12-14 11:06:51 【问题描述】:基于
Amazon Redshift announces support for lateral column alias reference:
对横向列别名引用的支持使您能够编写查询而无需在 SELECT 列表中重复相同的表达式。例如,您可以定义别名“概率”并在同一个选择语句中使用它:
select clicks / impressions as probability, round(100 * probability, 1) as percentage from raw_data;
基本相同:
select 1 AS col
,col + 1 AS col2;
db<>fiddle demo
大多数 SQL RDBMS 将返回错误:Unknown column 'col' in 'field list'
它看起来像一个有趣的语言扩展,但有一个警告。如果我有一个不确定的函数怎么办:
select RAND() AS col
,col + 1 AS col2
-- if RAND() returns 0.5 then I would expect
-- 0.5 and 1.5
-- I get: 0.3 and 1.7
-- it means that the query was evaluated as:
select RAND() AS col,
RAND() + 1 AS col2
与来自 PostgreSQL 的 LATERAL JOIN
相比(是的,我知道这是不同的功能,我希望“横向库别名”的行为方式相同):
SELECT s.col, s.col+1 AS col2
FROM t ,LATERAL (SELECT RANDOM()) AS s(col)
-- 0.19089933477628307 1.190899334776283
db<>fiddle demo
但事实并非如此。我得到了两个独立的运行,如果它是简单的“内联”,这似乎是有效的:
SELECT List
别名在目标列表中定义后立即被识别。您可以在同一目标列表中定义的其他表达式中使用别名。以下示例说明了这一点。
横向别名引用的好处是在同一个目标列表中构建更复杂的表达式时,您不需要重复别名表达式。当 Amazon Redshift 解析这种类型的引用时,它只是内联先前定义的别名。如果 FROM 子句中定义的列与先前的别名表达式具有相同的名称,则 FROM 子句中的列优先。
当我们使用不确定或时间敏感的函数/引用/子查询时,我的理解是否正确并且此功能不“安全”?
【问题讨论】:
我对该文档的阅读是-正如您所见-select RAND() AS col ,col + 1 AS col2
被视为select RAND() AS col, RAND() + 1 AS col2
或一般select (some expression) AS col, (some expression) + 1 AS col2
【参考方案1】:
这种语法不安全。事实上,仅仅内联代码意味着它甚至没有提供性能优势。它只是语法糖。
鉴于有简单的替代方案——CTE 和子查询——我会避免这个新的“功能”。
如果有设置可以关闭它,我建议使用它。
顺便说一下,许多 SQL 新手都觉得这很令人不安。这个目的是为了避免歧义。下面的查询应该返回什么?
select (a + 1) as b, b
from (select 1 as a, 0 as b) x;
SQL 的设计者可能认为解决此类情况的规则比仅仅重写子查询更复杂。
据我所知,能够很好地解决这个问题的“数据库”实际上是 SAS proc SQL
。它引入了calculated
关键字,所以你可以这样写:
select (a + 1) as b, calculated b, b
from (select 1 as a, 0 as b) x;
这将返回2, 2, 0
。
换句话说,我认为亚马逊在实现这个“功能”时并没有考虑太多。
【讨论】:
您的整个论点取决于多次重复使用同一列别名;似乎这是真正的糟糕做法。【参考方案2】:为什么不使用With
子句来更好地理解可重用性,因为这是您应该在运行时执行别名可重用性的方式。
With Data
As (Select count( *) from table)
Select Data+1, Data from table
关于上述横向参考的使用,如果你的意思是安全的话。没有什么安全的,因为您仍然会在同一个选择中定义一些表达式以便能够在其他列中使用它。只是它也是一种选择。没有这样的声明是安全的,因为它在运行时是显式且易受攻击的。为了安全起见,您应该将数据表达式存储在某种函数或过程中,并对其具有访问权限,就像我们拥有 Max() 等隐式函数/过程一样。但是,出于其他目的,我猜 with would be less time consuming than above amazon redshift functionality as it runs inline
所以它会运行每次一行一行
【讨论】:
感谢您的回答,但这个具体案例不是关于替代方法的问题(cte、子查询、横向连接——我已经知道了)。另外,如果您还有一个参考,您将需要使用两次cte
,其中横向列别名将允许:SELECT 1 AS col1, col1+1 AS col2, col2 +1 AS col3, ...
在单行中。
现在编辑我的答案检查以上是关于Amazon Redshift - 横向列别名参考的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Redshift 的结果中保留列别名中的大写和小写字母