Snowflake is throwing an error for an EXISTS clause if a filter condition depends on coalescing columns from both the outer table and the subquery table. The query will run if I remove the outer-table column from the COALESCE or replace the COALESCE with the long-form equivalent logic.
I'm seeing this error, specifically SQL compilation error: Unsupported subquery type cannot be evaluated, for what I would consider to be a fairly straightforward WHERE EXISTS clause. This would work in every (recent) SQL variant that I've used (e.g., SQL Server, Postgres), so I'm a little concerned that Snowflake doesn't support it. Am I missing something?
I found what seems to be a similar question at Snowflake's Community in 2019, where Snowflake was failing when the EXISTS clause included a WHERE filter condition that referenced a column from an outer query for something other than joining the tables. There was not a clear solution there.
Snowflake's documentation on its limited support for subqueries says that it supports both correlated and uncorrelated subqueries for "EXISTS, ANY / ALL, and IN subqueries in WHERE clauses".
So why is it failing on this EXISTS clause? Is what I'm seeing a bug, or is this a Snowflake limitation that is not clearly documented?
Code to reproduce the issue:
CREATE OR REPLACE TEMPORARY TABLE Employee (
Emp_SK INT NOT NULL
);
CREATE OR REPLACE TEMPORARY TABLE Employee_X_Pay_Rate (
Emp_SK INT NOT NULL, Pay_Rate_SK INT NOT NULL, Start_Date TIMESTAMP_NTZ NOT NULL, End_Date TIMESTAMP_NTZ NOT NULL
);
CREATE OR REPLACE TEMPORARY TABLE Employee_X_Location (
Emp_SK INT NOT NULL, Location_SK INT NOT NULL, Start_Date TIMESTAMP_NTZ NOT NULL, End_Date TIMESTAMP_NTZ NULL
);
INSERT INTO Employee
VALUES (1);
INSERT INTO Employee_X_Pay_Rate
VALUES
(1, 1, '2018-01-01', '2019-03-31')
,(1, 2, '2019-04-01', '2021-03-31')
,(1, 3, '2021-04-01', '2099-12-31')
;
INSERT INTO Employee_X_Location
VALUES
(1, 101, '2018-01-01', '2019-12-31')
,(1, 102, '2020-01-01', '2020-12-31')
,(1, 103, '2021-01-01', NULL)
;
SET Asof_Date = TO_DATE('2021-05-31', 'yyyy-mm-dd'); -- changing this to TO_TIMESTAMP makes no difference
SELECT
emp.Emp_SK
,empPay.Pay_Rate_SK
,$Asof_Date AS Report_Date
,empPay.Start_Date AS Pay_Start_Date
,empPay.End_Date AS Pay_End_Date
FROM Employee emp
INNER JOIN Employee_X_Pay_Rate empPay
ON emp.Emp_SK = empPay.Emp_SK
AND $Asof_Date BETWEEN empPay.Start_Date AND empPay.End_Date
WHERE EXISTS (
SELECT 1 FROM Employee_X_Location empLoc
WHERE emp.Emp_SK = empLoc.Emp_SK
-- Issue: Next line fails. empLoc.End_Date can be null
AND $Asof_Date BETWEEN empLoc.Start_Date AND COALESCE(empLoc.End_Date, empPay.End_Date)
);
The query will run if I replace the issue line with either of the following.
-- Workaround 1
AND (
$Asof_Date >= empLoc.Start_Date
AND ($Asof_Date <= empLoc.End_Date OR (empLoc.End_Date IS NULL AND $Asof_Date <= empPay.End_Date))
)
-- Workaround 2
AND $Asof_Date BETWEEN empLoc.Start_Date AND COALESCE(empLoc.End_Date, CURRENT_DATE)