Consider the following table/dataframe:
|------------------|
|date | value|
|------------------|
|2022-01-08 | 2 |
|2022-01-09 | 4 |
|2022-01-10 | 6 |
|2022-01-11 | 8 |
-------------------|
And the following SQL query:
WHILE (@start_date <= @end_date)
BEGIN
update t1 set value =
IIF(ISNULL(avg_value,0) < 2, 0,1)
from #table t1
outer apply (
select
top 1 value as avg_value
FROM
#table t2
WHERE
value >= 2 AND
t2.date < t1.date
ORDER BY date DESC
) t3
where t1.date = @start_date
SET @start_date = dateadd(day,1, @start_date)
END
I know my output is:
|------------------------------|
|date | value | avg_value|
|------------------------------|
|2022-01-08 | 0 | null |
|2022-01-09 | 0 | 0 |
|2022-01-10 | 0 | 0 |
|2022-01-11 | 0 | 0 |
|------------------------------|
The query runs an outer apply for each date, so the table is updated line-by-line. It is worth mentioning that the value updated is retrieved within outer apply.
In Spark, I get the values from outer apply using Window function and store it in an auxiliary column:
|-------------------------------|
|date | value | avg_value |
|-------------------------------|
|2022-01-08 | 0 | null |
|2022-01-09 | 4 | 2 |
|2022-01-10 | 6 | 4 |
|2022-01-11 | 8 | 6 |
|-------------------------------|
Then I use withColumn to perform the update on value column, my output is:
|-------------------|
|date | value |
|--------------------
|2022-01-08 | 0 |
|2022-01-09 | 1 |
|2022-01-10 | 1 |
|2022-01-11 | 1 |
|-------------------|
I KNOW my Spark output is different from SQL output, because SQL performs the update in each iteration, and in Spark's case I'm doing the update after all the avg_value are calculated.
MY QUESTION IS:
Is there a way to perform this query without using while loops, more specifically, is there a way to use update row-by-row in Spark?
My original DF has about 300K lines and I'm avoiding to use loops due to performance reasons.