为什么我的子查询只能使用字符串,而不能使用字段引用?

时间:2019-06-08 01:12:29

标签: sql snowflake-datawarehouse

我有(我认为是)一个相当复杂的查询。该查询获取我想要的记录,然后获取第一个响应中引用的所有数据。如果我的条件子查询是字符串,则有效,但如果它是一个字段(具有完全相同的值),则无效。

// Query with string as conditional in lowest sub-query (4th line from the bottom)

SELECT 
     e1.entity as entity
    ,ARRAY_CAT(
      ARRAY_COMPACT( 
        ARRAY_CONSTRUCT( 
          any_value(e2.entity), 
          any_value(u1.user) 
        )
      )
      ,ARRAY_AGG(e3.entity)
    ) as includes
FROM ENTITIES e1
LEFT JOIN ENTITIES e2 ON e1.entity:owner:workspace = e2.entity:id
LEFT JOIN USERS u1 ON e1.entity:owner:user = u1.user:id
LEFT JOIN ENTITIES e3 ON e3.entity:id IN (
  SELECT ee2.value FROM 
  table(FLATTEN( input=> 
    SELECT SPLIT(LISTAGG( CASE WHEN IS_ARRAY(ee1.value:id) THEN ARRAY_TO_STRING(ee1.value:id, ',') ELSE ee1.value:id END, ','), ',') 
    FROM table(FLATTEN( input => ( SELECT e4.entity:relationships:entities FROM ENTITIES e4 WHERE e4.entity:id = 'bd265f29-ca32-449a-b765-bb488e4d6b3c' ) )) ee1
  )) ee2
)
GROUP BY e1.entity

以上内容产生:

“实体”列: https://jsonblob.com/6d98b587-8989-11e9-b738-a9487a0dac0b

“包含”列: https://jsonblob.com/068a8672-8988-11e9-b738-77f0e471310b

但是,如果将uuid字符串(bd265f29-ca32-449a-b765-bb488e4d6b3c)更改为e1.entity:id(如下),则会收到错误SQL compilation error: Unsupported subquery type cannot be evaluated

SELECT 
     e1.entity as entity
    ,ARRAY_CAT(
      ARRAY_COMPACT( 
        ARRAY_CONSTRUCT( 
          any_value(e2.entity), 
          any_value(u1.user) 
        )
      )
      ,ARRAY_AGG(e3.entity)
    ) as includes
FROM ENTITIES e1
LEFT JOIN ENTITIES e2 ON e1.entity:owner:workspace = e2.entity:id
LEFT JOIN USERS u1 ON e1.entity:owner:user = u1.user:id
LEFT JOIN ENTITIES e3 ON e3.entity:id IN (
  SELECT ee2.value FROM 
  table(FLATTEN( input=> 
    SELECT SPLIT(LISTAGG( CASE WHEN IS_ARRAY(ee1.value:id) THEN ARRAY_TO_STRING(ee1.value:id, ',') ELSE ee1.value:id END, ','), ',') 
    FROM table(FLATTEN( input => ( SELECT e4.entity:relationships:entities FROM ENTITIES e4 WHERE e4.entity:id = e1.entity:id ) )) ee1
  )) ee2
)
GROUP BY e1.entity

我不知道为什么交换机会导致错误。为什么我的子查询只能使用字符串,而不能使用字段引用?

4 个答案:

答案 0 :(得分:1)

因此,使用几个 CTE 来提供数据,何时可以完成大部分相关子查询的提升。我将两种形式的事物数组都放在实体中,并在您的 FLATTEN 用法中表示了具有多个 id 的单个实体:

WITH users AS (
    SELECT parse_json('{"id":1}') as user
), entities AS (
    SELECT parse_json(column1) as entity 
    FROM VALUES
        ('{"id":10, "relationships":{"entities":[{"id":11},{"id":12}]}, "owner":{"user":1,"workspace":10}}'),
        ('{"id":11, "relationships":{"entities":[{"id":11}]}}'),
        ('{"id":12, "relationships":{"entities":[{"id":[10,11]}]}}')
), ent1 AS (
    SELECT e4.entity:id as ent_id
        ,ee1.index
        ,SPLIT(LISTAGG( IFF( IS_ARRAY(ee1.value:id), ARRAY_TO_STRING(ee1.value:id, ','), ee1.value:id), ','), ',') as vals
    FROM ENTITIES AS e4, 
    TABLE(FLATTEN( input => e4.entity:relationships:entities )) ee1
    GROUP BY 1,2
), ent_rels AS (
    SELECT ent_id, ee2.value::number as rel_id
    FROM ent1 ee1,
    TABLE(FLATTEN( input => ee1.vals)) ee2
)
SELECT 
    e1.entity:id as entity
    ,e2.entity:id as e2_entity
    ,u1.user:id as u1_user
    ,e3.entity:id as e3_entity
FROM ENTITIES e1
LEFT JOIN ENTITIES e2 ON e1.entity:owner:workspace = e2.entity:id
LEFT JOIN USERS u1 ON e1.entity:owner:user = u1.user:id
LEFT JOIN ent_rels er ON er.ent_id = e1.entity:id
LEFT JOIN ENTITIES e3 ON e3.entity:id = er.rel_id
ORDER BY e1.entity:id;

所以此 SQL 不是您拥有的选择结果,但确实显示了按预期加入的内容。

ENTITY    E2_ENTITY    U1_USER    E3_ENTITY
10        10           1          11
10        10           1          12
11        null         null       11
12        null         null       10
12        null         null       11

所以这个最终选择是你原来的方式

SELECT 
     e1.entity as entity
    ,ARRAY_CAT(
      ARRAY_COMPACT( 
        ARRAY_CONSTRUCT( 
          any_value(e2.entity), 
          any_value(u1.user) 
        )
      )
      ,ARRAY_AGG(e3.entity)
    ) as includes
FROM ENTITIES e1
LEFT JOIN ENTITIES e2 ON e1.entity:owner:workspace = e2.entity:id
LEFT JOIN USERS u1 ON e1.entity:owner:user = u1.user:id
LEFT JOIN ent_rels er ON er.ent_id = e1.entity:id
LEFT JOIN ENTITIES e3 ON e3.entity:id = er.rel_id
GROUP BY e1.entity
ORDER BY e1.entity:id;

另外,考虑到您正在撤消两层嵌套以获得匹配的 ID,您可以避免使用 LISTAGG 和 SPLITS 并通过以下方式将它们分解:

), ent1 AS (
    SELECT e4.entity:id as ent_id
        ,ee1.value:id as vals
    FROM ENTITIES AS e4, 
    TABLE(FLATTEN( input => e4.entity:relationships:entities )) ee1

), ent_rels AS (
    SELECT ent_id
        ,coalesce(ee2.value,ee1.vals) as rel_id
    FROM ent1 ee1,
    TABLE(FLATTEN( input => ee1.vals, outer => true)) ee2
)

如果这是您的偏好,可以合并/嵌套:

, ent_rels AS (
    SELECT ent_id
        ,coalesce(ee3.value,ee2.vals) as rel_id
    FROM (
      SELECT e1.entity:id as ent_id
        ,ee1.value:id as vals
        FROM ENTITIES AS e1, 
        TABLE(FLATTEN( input => e1.entity:relationships:entities )) ee1
    ) ee2,
    TABLE(FLATTEN( input => ee2.vals, outer => true)) ee3
)

答案 1 :(得分:0)

子查询上的雪花documentation包括以下限制:

  

仅当可以静态确定相关标量子查询返回一行时(例如,如果SELECT列表包含不带GROUP BY的聚合函数),当前才支持相关标量子查询。

所以您可以尝试:





  <ion-content  class="background">


  <img src="../assets/imgs/bas1.png"/>
<ion-card>

<ion-card-header>
  SIGNUP
</ion-card-header>
    <ion-card-content>

      <ion-list no-line>
         <form [formGroup]="myForm" novalidate >
        <ion-item>

          <ion-input input type="text" placeholder="Name" formControlName="name"></ion-input>
        </ion-item>
<ion-item no-lines *ngIf="( myForm.get('name').hasError('minlength') || myForm.get('name').hasError('required') ) && myForm.get('name').touched">

<div class="error" *ngIf="myForm.get('name').hasError('required') && myForm.get('name').touched">
Name is required
</div>
<div class="error" *ngIf="myForm.get('name').hasError('minlength') && myForm.get('name').touched">
Maximum of 6 characters
</div>
</ion-item>

        <ion-item>

          <ion-input input type="text" placeholder="Username" formControlName="username"></ion-input>
        </ion-item>
        <ion-item no-lines *ngIf="( myForm.get('username').hasError('minlength') || myForm.get('username').hasError('required') ) && myForm.get('username').touched">

<div class="error" *ngIf="myForm.get('username').hasError('required') && myForm.get('username').touched">
username is required
</div>
<div class="error" *ngIf="myForm.get('username').hasError('minlength') && myForm.get('username').touched">
Minimum of 6 characters
</div>
</ion-item>

          <ion-item>

            <ion-input type="email" placeholder="E-mail" formControlName="email"></ion-input>
          </ion-item>

           <ion-item no-lines *ngIf="( myForm.get('email').hasError('email') || myForm.get('email').hasError('required') ) && myForm.get('email').touched">

<div class="error" *ngIf="myForm.get('email').hasError('required') && myForm.get('username').touched">
email is required
</div>
<div class="error" *ngIf="myForm.get('email').hasError('email') && myForm.get('email').touched">
Enter valid email
</div>
</ion-item>
<ion-item>

            <ion-input type="password" placeholder="Password" formControlName="password"></ion-input>
          </ion-item>
 <ion-item no-lines *ngIf="( myForm.get('password').hasError('required') ) && myForm.get('password').touched">

<div class="error" *ngIf="myForm.get('password').hasError('required') && myForm.get('password').touched">
password is required
</div>

</ion-item>

          <ion-item>

            <ion-input type="password" placeholder="confirmPassword" formControlName="confirmpassword"></ion-input>
          </ion-item>
          <ion-item no-lines *ngIf="( myForm.get('confirmpassword').hasError('required') ) && myForm.get('confirmpassword').touched">

<div class="error" *ngIf="myForm.get('confirmpassword').hasError('required') && myForm.get('confirmpassword').touched">
password should match
</div>

</ion-item>


</form>


        <button ion-button block class="google" (click)="onSubmit(myForm)">SIGN-UP</button>
</ion-list>
    </ion-card-content>

</ion-card>

</ion-content>

<style type="text/css">
.error
{
color:red;
}

</style>

答案 2 :(得分:0)

您是否尝试过像这样投射它?

e1.entity:id::string

答案 3 :(得分:0)

Snowflake文档中提到:

  

目前在FLATTEN内部具有相关性的子查询   不支持。

您不能简单地使用e1.entity:relationships:entities代替子查询吗?