|  | 
| 40 | 40 | {% macro bq_insert_overwrite_sql( | 
| 41 | 41 |     tmp_relation, target_relation, sql, unique_key, partition_by, partitions, dest_columns, tmp_relation_exists, copy_partitions | 
| 42 | 42 | ) %} | 
| 43 |  | -  {% if partitions is not none and partitions != [] %} {# static #} | 
| 44 |  | -      {{ bq_static_insert_overwrite_sql(tmp_relation, target_relation, sql, partition_by, partitions, dest_columns, tmp_relation_exists, copy_partitions) }} | 
| 45 |  | -  {% else %} {# dynamic #} | 
| 46 |  | -      {{ bq_dynamic_insert_overwrite_sql(tmp_relation, target_relation, sql, unique_key, partition_by, dest_columns, tmp_relation_exists, copy_partitions) }} | 
| 47 |  | -  {% endif %} | 
|  | 43 | + | 
|  | 44 | +    {# static #} | 
|  | 45 | +    {% if partitions is not none and partitions != [] %} | 
|  | 46 | +        {{ bq_static_insert_overwrite_sql(tmp_relation, target_relation, sql, partition_by, partitions, dest_columns, tmp_relation_exists, copy_partitions) }} | 
|  | 47 | + | 
|  | 48 | +    {# dynamic #} | 
|  | 49 | +    {% else %} | 
|  | 50 | +        {{ bq_dynamic_insert_overwrite_sql(tmp_relation, target_relation, sql, unique_key, partition_by, dest_columns, tmp_relation_exists, copy_partitions) }} | 
|  | 51 | +    {% endif %} | 
|  | 52 | + | 
| 48 | 53 | {% endmacro %} | 
| 49 | 54 | 
 | 
| 50 |  | -{% macro bq_static_insert_overwrite_sql( | 
| 51 |  | -    tmp_relation, target_relation, sql, partition_by, partitions, dest_columns, tmp_relation_exists, copy_partitions | 
|  | 55 | +{# | 
|  | 56 | +    -- static partitions refer to a fixed set of partition values that are | 
|  | 57 | +    -- known ahead of time and do not depend on source data or runtime | 
|  | 58 | +    -- conditions. these values are typically hardcoded or configured | 
|  | 59 | +    -- externally (e.g., via dbt variables or macros). | 
|  | 60 | +    -- | 
|  | 61 | +    -- with `insert_overwrite`, dbt uses a predefined partition filter | 
|  | 62 | +    -- expression to overwrite specific partitions | 
|  | 63 | +    -- (e.g., where partition_column = '2024-05-01'). | 
|  | 64 | +    -- it excels where using a fixed minimal partition list, no need to | 
|  | 65 | +    -- query source data for partitions, and insert statements can be | 
|  | 66 | +    -- batched. this also keeps things deterministic. | 
|  | 67 | +#} | 
|  | 68 | + | 
|  | 69 | +{% macro bq_static_select_insert_overwrite_sql(tmp_relation, sql, partition_by, tmp_relation_exists) %} | 
|  | 70 | +  {%- set source_sql -%} | 
|  | 71 | +  ( | 
|  | 72 | +    {% if tmp_relation_exists %} | 
|  | 73 | +      select | 
|  | 74 | +        {% if partition_by.time_ingestion_partitioning %} | 
|  | 75 | +          {{ partition_by.insertable_time_partitioning_field() }}, | 
|  | 76 | +        {% endif %} | 
|  | 77 | +        * from {{ tmp_relation }} | 
|  | 78 | +    {%- elif partition_by.time_ingestion_partitioning -%} | 
|  | 79 | +      {{ wrap_with_time_ingestion_partitioning_sql(partition_by, sql, true) }} | 
|  | 80 | +    {%- else -%} | 
|  | 81 | +      {{ sql }} | 
|  | 82 | +    {%- endif %} | 
|  | 83 | +  ) | 
|  | 84 | +  {%- endset -%} | 
|  | 85 | +  {{ return(source_sql) }} | 
|  | 86 | +{% endmacro %} | 
|  | 87 | + | 
|  | 88 | + | 
|  | 89 | +{# | 
|  | 90 | +  -- Static-partition + `copy_partitions=true` should inline the literals / foldable constants | 
|  | 91 | +  -- supplied via the `partitions=` config. | 
|  | 92 | + | 
|  | 93 | +  -- The inline method will still copy (truncate) a partition even | 
|  | 94 | +  -- if the incremental run produced no rows for that date, because the user | 
|  | 95 | +  -- explicitly listed it in `partitions=`. | 
|  | 96 | +#} | 
|  | 97 | +{% macro bq_static_copy_partitions_insert_overwrite_sql( | 
|  | 98 | +  tmp_relation, target_relation, sql, partition_by, partitions, tmp_relation_exists | 
| 52 | 99 | ) %} | 
| 53 | 100 | 
 | 
| 54 |  | -      {% set predicate -%} | 
| 55 |  | -          {{ partition_by.render_wrapped(alias='DBT_INTERNAL_DEST') }} in ( | 
| 56 |  | -              {{ partitions | join (', ') }} | 
| 57 |  | -          ) | 
| 58 |  | -      {%- endset %} | 
|  | 101 | +    {%- if tmp_relation_exists is false -%} | 
|  | 102 | +        {%- set source_sql = bq_static_select_insert_overwrite_sql(tmp_relation, sql, partition_by, tmp_relation_exists) %} | 
| 59 | 103 | 
 | 
| 60 |  | -      {%- set source_sql -%} | 
| 61 |  | -        ( | 
| 62 |  | -          {% if partition_by.time_ingestion_partitioning and tmp_relation_exists -%} | 
| 63 |  | -          select | 
| 64 |  | -            {{ partition_by.insertable_time_partitioning_field() }}, | 
| 65 |  | -            * from {{ tmp_relation }} | 
| 66 |  | -          {% elif tmp_relation_exists -%} | 
| 67 |  | -            select | 
| 68 |  | -            * from {{ tmp_relation }} | 
| 69 |  | -          {%- elif partition_by.time_ingestion_partitioning -%} | 
| 70 |  | -            {{ wrap_with_time_ingestion_partitioning_sql(partition_by, sql, True) }} | 
| 71 |  | -          {%- else -%} | 
| 72 |  | -            {{sql}} | 
| 73 |  | -          {%- endif %} | 
| 74 |  | - | 
| 75 |  | -        ) | 
| 76 |  | -      {%- endset -%} | 
|  | 104 | +        {# -- we run temp table creation in a separate script to move to partitions copy if it doesn't already exist #} | 
|  | 105 | +        {%- call statement('create_tmp_relation_for_copy', language='sql') -%} | 
|  | 106 | +          {{ bq_create_table_as(partition_by, true, tmp_relation, source_sql, 'sql') | 
|  | 107 | +        }} | 
|  | 108 | +        {%- endcall %} | 
|  | 109 | +    {%- endif -%} | 
| 77 | 110 | 
 | 
| 78 |  | -      {% if copy_partitions %} | 
| 79 |  | -          {% do bq_copy_partitions(tmp_relation, target_relation, partitions, partition_by) %} | 
| 80 |  | -      {% else %} | 
|  | 111 | +    {%- set partitions_sql -%} | 
|  | 112 | +	select | 
|  | 113 | +	    cast(partition_literal as timestamp) as partition_ts | 
|  | 114 | +	from unnest([ | 
|  | 115 | +	    {{ partitions | join(', ') }} | 
|  | 116 | +	]) as partition_literal | 
|  | 117 | +    {%- endset -%} | 
| 81 | 118 | 
 | 
| 82 |  | -      {#-- In case we're putting the model SQL _directly_ into the MERGE statement, | 
| 83 |  | -         we need to prepend the MERGE statement with the user-configured sql_header, | 
| 84 |  | -         which may be needed to resolve that model SQL (e.g. referencing a variable or UDF in the header) | 
| 85 |  | -         in the "temporary table exists" case, we save the model SQL result as a temp table first, wherein the | 
| 86 |  | -         sql_header is included by the create_table_as macro. | 
| 87 |  | -      #} | 
| 88 |  | -      -- 1. run the merge statement | 
| 89 |  | -      {{ get_insert_overwrite_merge_sql(target_relation, source_sql, dest_columns, [predicate], include_sql_header = not tmp_relation_exists) }}; | 
|  | 119 | +    {%- set resolved_partitions = run_query(partitions_sql).columns[0].values() -%} | 
| 90 | 120 | 
 | 
| 91 |  | -      {%- if tmp_relation_exists -%} | 
| 92 |  | -      -- 2. clean up the temp table | 
| 93 |  | -      drop table if exists {{ tmp_relation }}; | 
| 94 |  | -      {%- endif -%} | 
|  | 121 | +    {% do bq_copy_partitions(tmp_relation, target_relation, resolved_partitions, partition_by) %} | 
| 95 | 122 | 
 | 
| 96 |  | -  {% endif %} | 
|  | 123 | +    {# clean up temp table #} | 
|  | 124 | +    drop table if exists {{ tmp_relation }} | 
| 97 | 125 | {% endmacro %} | 
| 98 | 126 | 
 | 
|  | 127 | + | 
|  | 128 | +{% macro bq_static_insert_overwrite_sql( | 
|  | 129 | +    tmp_relation, target_relation, sql, partition_by, partitions, dest_columns, tmp_relation_exists, copy_partitions | 
|  | 130 | +) %} | 
|  | 131 | + | 
|  | 132 | +    {%- if copy_partitions %} | 
|  | 133 | +        {{ bq_static_copy_partitions_insert_overwrite_sql(tmp_relation, target_relation, sql, partition_by, partitions, tmp_relation_exists) }} | 
|  | 134 | +    {% else -%} | 
|  | 135 | +        {% set predicate -%} | 
|  | 136 | +            {{ partition_by.render_wrapped(alias='dbt_internal_dest') }} in ( | 
|  | 137 | +                {{ partitions | join (', ') }} | 
|  | 138 | +            ) | 
|  | 139 | +        {%- endset %} | 
|  | 140 | + | 
|  | 141 | +        {%- set source_sql = bq_static_select_insert_overwrite_sql(tmp_relation, sql, partition_by, tmp_relation_exists) %} | 
|  | 142 | +	{# | 
|  | 143 | +	  -- when the model sql is inserted directly into the merge statement, | 
|  | 144 | +	  -- we need to prepend it with the user-defined `sql_header`. this is | 
|  | 145 | +	  -- important when the model sql references elements like variables or udfs | 
|  | 146 | +	  -- defined in the header. | 
|  | 147 | + | 
|  | 148 | +	  -- in the case where a temporary table is created first (i.e., the | 
|  | 149 | +	  -- "temp table exists" path), the `sql_header` is already included via | 
|  | 150 | +	  -- the `create_table_as` macro, so no additional handling is needed. | 
|  | 151 | +	#} | 
|  | 152 | + | 
|  | 153 | +        -- 1. run the merge statement | 
|  | 154 | +        {{ get_insert_overwrite_merge_sql(target_relation, source_sql, dest_columns, [predicate], include_sql_header = not tmp_relation_exists) }}; | 
|  | 155 | + | 
|  | 156 | +        {%- if tmp_relation_exists -%} | 
|  | 157 | +        -- 2. clean up the temp table | 
|  | 158 | +        drop table if exists {{ tmp_relation }}; | 
|  | 159 | +        {%- endif -%} | 
|  | 160 | + | 
|  | 161 | +    {%- endif -%} | 
|  | 162 | +{% endmacro %} | 
|  | 163 | + | 
|  | 164 | + | 
|  | 165 | +{# | 
|  | 166 | +    -- dynamic partitions refer to the set partition values that are | 
|  | 167 | +    -- determined at runtime, based on either the contents of source | 
|  | 168 | +    -- data (e.g. values in an updated_date column) or external runtime | 
|  | 169 | +    -- parameters (e.g. time of day, system params). | 
|  | 170 | +    -- | 
|  | 171 | +    -- with `insert_overwrite`, this allows dbt to compute which | 
|  | 172 | +    -- partitions to overwrite dynamically using a partition filter | 
|  | 173 | +    -- expression (e.g., where partition_column >= current_date()). | 
|  | 174 | +    -- | 
|  | 175 | +    -- this enables targeted incremental updates by overwriting only the | 
|  | 176 | +    -- affected partitions, rather than replacing the entire table. | 
|  | 177 | +    -- this reduces latency and cost by limiting the scope of writes. | 
|  | 178 | +#} | 
|  | 179 | + | 
|  | 180 | + | 
| 99 | 181 | {% macro bq_dynamic_copy_partitions_insert_overwrite_sql( | 
| 100 | 182 |   tmp_relation, target_relation, sql, unique_key, partition_by, dest_columns, tmp_relation_exists, copy_partitions | 
| 101 | 183 |   ) %} | 
|  | 
0 commit comments