Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Snowflake subquery

I have two tables. Transaction(ID, TERMINALID) and Terminal(ID, TERMINALID, EXPORT_DATE). The goal is to obtain for each row from Transaction table newest recored from Terminal table. Snowflake is used as a backend.

I have this SQL query:

SELECT tr.ID,
       (SELECT te.ID
        FROM "Terminal" te
        WHERE te.TERMINALID = tr.TERMINALID
        ORDER BY te.EXPORT_DATE DESC
        LIMIT 1)
FROM "Transaction" tr;

But I get this error:

SQL compilation error: Unsupported subquery type cannot be evaluated

Error disappears if I replace tr.TERMINALID with a specific value. So I can't reference parent table from nested SELECT. Why this is not possible? Query works in MySQL.

like image 874
michal4 Avatar asked Dec 21 '16 13:12

michal4


People also ask

Does Snowflake support subquery?

Snowflake currently supports the following types of subqueries: Uncorrelated scalar subqueries in any place that a value expression can be used. Correlated scalar subqueries in WHERE clauses. EXISTS, ANY / ALL, and IN subqueries in WHERE clauses.

How do you write a sub query in a Snowflake?

Subqueries in Snowflake can be defined by wrapping parentheses around a query and putting that query, with the parentheses around it, in a FROM or WHERE statement of the overall query. In the example above the subquery returns a single value. We can also return several values.

Is subquery better than CTE?

Advantage of Using CTE CTE can be more readable: Another advantage of CTE is CTE are more readable than Subqueries. Since CTE can be reusable, you can write less code using CTE than using subquery. Also, people tend to follow the logic and ideas easier in sequence than in a nested fashion.


1 Answers

I'm afraid Snowflake doesn't support correlated subqueries of this kind.

You can achieve what you want by using FIRST_VALUE to compute best per-terminalid id :

-- First compute per-terminalid best id
with sub1 as (
  select 
    terminalid, 
    first_value(id) over (partition by terminalid order by d desc) id
  from terminal 
),
-- Now, make sure there's only one per terminalid id
sub2 as (
  select 
    terminalid, 
    any_value(id) id
  from sub1
  group by terminalid
)
-- Now use that result
select tr.ID, sub2.id
FROM "Transaction" tr
JOIN sub2 ON tr.terminalid = sub2.terminalid

You can run subqueries first to see what they do.

We're working on making our support for subqueries better, and possibly there's a simpler rewrite, but I hope it helps.

like image 84
Marcin Zukowski Avatar answered Sep 23 '22 00:09

Marcin Zukowski