BigQuery a un comportement spécifique au dialecte et des modes d’échec qui justifient une section dédiée dans CLAUDE.md. Ce ne sont pas des préférences de style — ce sont des règles qui, lorsqu’elles sont violées, produisent des bugs silencieux, des scans coûteux de tables entières ou des échecs de requêtes. Chaque instruction existe parce que Claude adoptera le mauvais comportement par défaut sans guidance explicite.
La section BigQuery de base
Ajoutez ce bloc à votre CLAUDE.md dbt lorsque vous tournez sur BigQuery :
## BigQuery specifics- Use GoogleSQL syntax (not legacy SQL)- Single quotes for strings, `!=` for inequality- Always filter on partition column in WHERE clauses- Avoid SELECT * in production models- For large tables, use incremental with insert_overwriteChaque ligne prévient une classe spécifique d’erreurs.
GoogleSQL vs. Legacy SQL
BigQuery supporte deux dialectes SQL : GoogleSQL (anciennement Standard SQL) et Legacy SQL. Legacy SQL est l’ancien dialecte de l’ère précoce de BigQuery. La plupart de la documentation utilise GoogleSQL, la plupart des nouvelles fonctionnalités n’existent qu’en GoogleSQL, et les deux dialectes ont de vraies différences de syntaxe qui produisent des erreurs lorsqu’ils sont mélangés.
Claude a vu suffisamment de contenu BigQuery pour utiliser généralement GoogleSQL par défaut — mais pas toujours. S’il a rencontré des patterns Legacy SQL dans les données d’entraînement ou s’il se perd dans une longue fenêtre de contexte, il peut glisser. L’instruction explicite l’empêche.
Les patterns Legacy SQL les plus courants à surveiller : les décorateurs de table (table@timestamp), les clauses FROM séparées par des virgules au lieu de JOIN, GROUP EACH BY et FLATTEN. Si vous voyez l’un de ceux-ci dans le SQL généré, ajoutez un rappel explicite à votre CLAUDE.md.
La règle du filtre de partition
C’est celle qui coûte de l’argent. Le pruning de partitions ne fonctionne que lorsque la clause WHERE contient une valeur littérale filtrant sur la colonne de partition. Si Claude écrit une requête qui scanne une table partitionnée entière — parce qu’il a oublié d’inclure un filtre de partition, ou parce qu’il a utilisé une sous-requête ou une fonction dans le filtre — la requête s’exécute correctement mais coûte des ordres de grandeur de plus que nécessaire.
L’instruction “always filter on partition column in WHERE clauses” est délibérément absolue. Vous voulez que Claude traite cela comme une contrainte dure plutôt qu’une suggestion.
Une version subtile de cette erreur : encapsuler la colonne de partition dans une fonction défait le pruning même quand l’intention est de filtrer par partition. Claude fait parfois cela lorsqu’il travaille avec des partitions de timestamp :
-- Ceci ne prune PAS, même si ça devrait le faireWHERE DATE(created_at) = '2025-01-01'
-- Ceci prune (si created_at est la colonne de partition)WHERE created_at >= '2025-01-01' AND created_at < '2025-01-02'Si votre équipe a un pattern standard pour le filtrage des partitions, incluez-le explicitement. Le rappel générique aide ; un exemple concret aide davantage.
Le bloc de configuration du modèle incrémental
Pour les grandes tables sur BigQuery, insert_overwrite est typiquement la bonne stratégie incrémentale. Claude connaît les modèles incrémentaux, mais sans template il pourrait choisir une stratégie différente ou manquer des propriétés de config spécifiques à BigQuery comme require_partition_filter.
Incluez directement le template de bloc de config dans CLAUDE.md :
## Partitioning template{{ config( materialized='incremental', incremental_strategy='insert_overwrite', partition_by={"field": "created_at", "data_type": "timestamp", "granularity": "day"}, require_partition_filter=true, cluster_by=["customer__id", "region"])}}Ce template encode plusieurs décisions à la fois :
insert_overwriteplutôt quemerge(meilleur pour les données d’événements, évite les scans coûteux de tables entières côté destination)require_partition_filter=true(force toutes les requêtes sur cette table à inclure un filtre de partition — applique le garde-fou de coût au niveau de la table, pas seulement au niveau de la requête)cluster_byavec la clé primaire et une colonne de filtre commune (évite les scans coûteux de cluster-miss dans les partitions)
La propriété require_partition_filter en particulier vaut la peine d’être incluse dans le template parce qu’il est facile de l’oublier et qu’elle a un impact significatif en aval : toute requête sur cette table sans filtre de partition échouera, ce qui force de bonnes habitudes sur tous ceux qui interrogent le modèle, pas seulement sur le modèle lui-même.
Guillemets de chaînes et opérateurs de comparaison
Deux petites différences de syntaxe qui produisent des erreurs en GoogleSQL lorsque Claude utilise la mauvaise forme :
Littéraux de chaînes : GoogleSQL utilise des guillemets simples pour les chaînes. Legacy SQL utilisait des guillemets doubles. Si Claude génère WHERE event_name = "page_view", cela fonctionnera dans certains contextes mais échouera dans d’autres (les guillemets doubles sont réservés aux identifiants en SQL standard). Incluez single quotes for strings explicitement.
Inégalité : GoogleSQL utilise !=. Legacy SQL utilisait <>. Les deux fonctionnent dans BigQuery, mais != est la forme standard pour GoogleSQL. C’est plus une préférence de style qu’un problème de correction, mais la cohérence compte lorsque SQLFluff lint vos modèles — spécifiez quelle forme utiliser.
SELECT * dans les modèles de production
SELECT * dans un modèle de production signifie que les changements de schéma dans les tables en amont se propagent silencieusement en aval. Une nouvelle colonne ajoutée à une source apparaît dans tous les marts sans test. Une colonne supprimée d’une source casse les modèles sans message d’erreur clair.
L’instruction appartient à CLAUDE.md plutôt que juste dans la documentation parce que Claude utilisera SELECT * comme raccourci lors de l’exploration ou lorsque l’invite n’aborde pas explicitement la sélection de colonnes. Le rendre explicite l’empêche lors de la génération de modèles.
L’exception : SELECT * EXCEPT (column_name) est utile dans les modèles de base pour supprimer les artefacts de staging. C’est un pattern différent et ne nécessite pas le même garde-fou.
Quand étendre cette section
Ces instructions couvrent les erreurs spécifiques à BigQuery les plus courantes. Ajoutez des instructions supplémentaires uniquement lorsque Claude fait une erreur spécifique qui n’est pas couverte.
Expansions courantes ajoutées par les équipes au fil du temps :
- Patterns de dépliage de tableaux (syntaxe
UNNEST()pour les champs répétés des exports GA4 ou Pub/Sub) SAFE_DIVIDE()au lieu de la division brute (évite ZeroDivisionError au moment de la requête)- Distinctions
TIMESTAMP_TRUNC()vsDATE_TRUNC() - Patterns de référence de dataset spécifiques au projet (guillemets backtick pour les références inter-projets)
Chacune de celles-ci vaut la peine d’être ajoutée seulement après que Claude a fait l’erreur réelle. Les instructions spéculatives consomment le budget d’instructions sans prévenir de vrais problèmes.
Relation avec les contrôles au niveau de l’entrepôt
Les instructions CLAUDE.md sont des directives pour Claude — elles façonnent le SQL généré, mais elles n’appliquent rien au niveau de l’infrastructure. Pour une vraie application, complétez votre CLAUDE.md avec :
maximum_bytes_billeddans profiles.yml — plafond dur sur les octets scannés par requêterequire_partition_filter=truesur les tables dans votre couche de base — force les filtres de partition au niveau de la requête indépendamment de qui écrit la requête- Quotas BigQuery au niveau du projet — plafonds quotidiens sur les octets traités
Les instructions disent à Claude ce qu’il faut faire. Les contrôles d’infrastructure l’appliquent indépendamment de ce que Claude fait.