Redshift Cross join忽略where子句

Posted

技术标签:

【中文标题】Redshift Cross join忽略where子句【英文标题】:Redshift Cross join ignoring where clause 【发布时间】:2020-02-03 16:05:44 【问题描述】:

我有以下疑问:

WITH MY_CTE as
(
select
....
.....
    )
SELECT
MY_CTE.*
,tt.currency as most_used_currency
from MY_CTE
cross join 
     (select t.currency
      from My_CTE t
      group by t.currency
      order by count(*) desc
      limit 1
     ) tt 
where MY_CTE.currency = 'EUR'

但是交叉连接忽略了我的 where 子句。 请问如何强制它在处理交叉连接之前处理 where 子句?

返回的样本数据:

这显然是错误的,因为我说不包括货币 SEK,但它却说它是最受欢迎的货币。 我不能将 where 子句放在交叉连接中,因为我将在 tableau 中使用它并且需要用户能够过滤某些条件,例如货币。

如果 MY_CTE 被过滤为仅显示欧元货币,则最受欢迎的货币应该是欧元

【问题讨论】:

也许问题是 SQL 中的比较是由单 = 执行的,而不是双 == 还要注意您正在查看的列:MY_CTE.currency 或 tt.currency。 tt.currency 值不会受到您的过滤器的影响。 有什么方法可以过滤交叉连接吗? 交叉连接是唯一不需要任何条件的连接。没有加入过滤器之类的东西。当您使用 join 时,您可以设置连接条件 on ..... 。过滤器是您在 SQL 的 WHERE ... 部分中定义的内容。如果您能提供数据样本和预期结果,也许会更容易理解。 编辑显示我得到的结果 【参考方案1】:

这种情况下的 WHERE 条件与交叉连接无关,它只是在连接已经执行后过滤行。如果您只需要报告单一货币,有两个最简单的选项来添加货币过滤器(在 SQL 中添加为 cmets):

1) 选项 1 - 在 CTE 语句中添加过滤器

2) 选项 2 - 在末尾添加过滤器(如已完成)和 tt 部分。

WITH MY_CTE as
(
select
....
.....
/* OPTION 1*/
    )
SELECT
MY_CTE.*
,tt.currency as most_used_currency
from MY_CTE
cross join 
     (select t.currency
      from My_CTE t
     /* OPTION 2 first place*/
      group by t.currency
      order by count(*) desc
      limit 1
     ) tt 
where MY_CTE.currency = 'EUR' /* OPTION 2a second place*/

【讨论】:

问题是我需要在画面中使用它,用户应该能够过滤货币和其他东西。所以它需要在外面(目前在哪里) 除非有一些选项可以使用 tableau 中的某些变量设置过滤器,否则从技术上讲,没有选项可以在 SQL 语句末尾进行过滤。在 postgresql(从 9.5 开始)中有聚合函数 mode() WITHIN GROUP (ORDER BY sort_expression),但 Redshift 中没有此类功能。在 Redshift 中也没有创建聚合用户定义函数的选项。【参考方案2】:

别名 tt 将返回总体上最受欢迎的货币,即 SEK。如果要过滤不同的货币,则需要将它们放入内部查询以及外部查询中。但是,如果这不是一个选项,您需要返回所有货币及其受欢迎程度,并筛选出您允许的最受欢迎的货币。

....
....
SELECT
LAST_VALUE(MY_CTE.customer_id) 
           OVER (partition by customer_id 
           ORDER BY tt.popularity
      rows between unbounded preceding and unbounded following) 
.... /* rest of your columns */
, LAST_VALUE(tt.currency) 
           OVER (partition by customer_id 
           ORDER BY tt.popularity
      rows between unbounded preceding and unbounded following) 
from MY_CTE
cross join 
 (select t.currency,
         count(*) popularity
      from My_CTE t
      group by t.currency
      order by count(*) desc
      /* removed limit 1 */
     ) tt 
where MY_CTE.currency = 'EUR' 
  AND tt.currency IN ('EUR') /* Added tt.currency filter */

【讨论】:

货币部分最受欢迎的原因是它也可以在没有货币过滤器的情况下运行。如果没有过滤器,它会产生不需要的笛卡尔积。

以上是关于Redshift Cross join忽略where子句的主要内容,如果未能解决你的问题,请参考以下文章

Redshift:将 FULL OUTER 替换为 CROSS JOIN

Redshift:FULL JOIN 忽略右表的 NULL

MySQL中inner join 和 cross join 的区别

CROSS JOIN,NATURAL JOIN

MySQL中inner join 和 cross join 的区别

Redshift 中的 update + case + join 语句