dbt-redshift icon indicating copy to clipboard operation
dbt-redshift copied to clipboard

[Feature] DBT Unit tests to support Redshift limitations such as LISTAGG, MEDIAN, PERCENTILE_CONT, etc.

Open tanapoln opened this issue 1 year ago • 0 comments

Is this your first time submitting a feature request?

  • [X] I have read the expectations for open source contributors
  • [X] I have searched the existing issues, and I could not find an existing issue for this feature
  • [X] I am requesting a straightforward extension of existing dbt functionality, rather than a Big Idea better suited to a discussion

Describe the feature

The current DBT Unit tests feature doesn't support Redshift if the SQL in CTE contains functions such as LISTAGG, MEDIAN, PERCENTILE_CONT, etc. Those functions must be executed against a user-created-table. However, DBT combines given rows to be part of CTE, which is unsupported by Redshift. You can try SQL below.

create temporary table "test_tmpxxxxx" as (
   with test_fixture as (
       select
         cast(1000 as integer) as id,
         cast('menu1' as character varying(500)) as name,
         cast( 1 as integer) as quantity
      union all
      select
         cast(1001 as integer) as id,
         cast('menu2' as character varying(500)) as name,
         cast( 1 as integer) as quantity
      union all
      select
         cast(1003 as integer) as id,
         cast('menu1' as character varying(500)) as name,
         cast( 1 as integer) as quantity
   ),
   agg as (
      SELECT
         LISTAGG(name || ' x ' || quantity, ',') AS option_name_list,
         id
      FROM test_fixture
      GROUP BY id
   )
   select * from agg
);

This will error [XX000] ERROR: One or more of the used functions must be applied on at least one user created tables. Examples of user table only functions are LISTAGG, MEDIAN, PERCENTILE_CONT, etc

But the query below works fine:

create temporary table "test_tmp1234" as (
   SELECT
      cast(1000 as integer) as id,
      cast('menu1' as character varying(500)) as name,
      cast( 1 as integer) as quantity
   union all
   select
      cast(1001 as integer) as id,
      cast('menu2' as character varying(500)) as name,
      cast( 1 as integer) as quantity
   union all
   select
      cast(1000 as integer) as id,
      cast('menu1' as character varying(500)) as name,
      cast( 1 as integer) as quantity
);

with agg as (
   SELECT
      LISTAGG(name || ' x ' || quantity, ',') AS option_name_list,
      id
   FROM test_tmp1234
   GROUP BY id
)
select * from agg;

As I mentioned, if all given rows are created as temporary table first, then run the test by referring to it, it will be fine.

This is a feature request to separate DBT unit tests into 2 steps

  1. Prepare test fixtures by creating temporary tables
  2. Run unit test query by referring to the temporary tables

Describe alternatives you've considered

No response

Who will this benefit?

No response

Are you interested in contributing this feature?

No response

Anything else?

No response

tanapoln avatar May 02 '24 11:05 tanapoln