2017-04-01 1 views
0

Supposons que j'ai deux tables: intervals contient des intervalles d'index (ses colonnes sont i_min et i_max) et values contient des valeurs indexées (avec des colonnes i et x). Voici un exemple:BigQuery/SQL: Somme des intervalles indiqués par une table secondaire

values:  intervals: 
+---+---+ +-------+-------+ 
| i | x | | i_min | i_max | 
+-------+ +---------------+ 
| 1 | 1 | | 1 | 4 | 
| 2 | 0 | | 6 | 6 | 
| 3 | 4 | | 6 | 6 | 
| 4 | 9 | | 6 | 6 | 
| 6 | 7 | | 7 | 9 | 
| 7 | 2 | | 12 | 17 | 
| 8 | 2 | +-------+-------+ 
| 9 | 2 | 
+---+---+ 

Je veux résumer les valeurs de x pour chaque intervalle:

 result: 
+-------+-------+-----+ 
| i_min | i_max | sum | 
+---------------------+ 
| 1 | 4 | 13 | // 1+0+4+9 
| 6 | 6 | 7 | 
| 6 | 6 | 7 | 
| 6 | 6 | 7 | 
| 7 | 9 | 6 | // 2+2+2 
| 12 | 17 | 0 | 
+-------+-------+-----+ 

Dans certains moteurs SQL, cela pourrait être fait en utilisant:

SELECT 
    i_min, 
    i_max, 
    (SELECT SUM(x) 
    FROM values 
    WHERE i BETWEEN intervals.i_min AND intervals.i_max) AS sum_x 
FROM 
    intervals 

sauf que type de requête n'est pas autorisé par BigQuery ("Subselect non autorisé dans la clause SELECT." ou "LEFT OUTER JOIN ne peut pas être utilisé sans une condition qui est une égalité des champs des deux côtés de la jointure." x utilisé).

Il doit y avoir un moyen de faire cela avec les fonctions de la fenêtre, mais je n'arrive pas à comprendre comment - tous les exemples que j'ai vus ont la partition comme partie de la table. Existe-t-il une option qui n'utilise pas CROSS JOIN? Si non, quel est le moyen le plus efficace de faire ce CROSS JOIN?

Quelques notes sur mes données:

  • Les deux tables contiennent beaucoup (10⁸-10⁹) lignes. Il peut y avoir des répétitions dans intervals, pas dans i.
  • Mais deux intervalles dans intervals sont les mêmes, soit entièrement disjoints (pas de chevauchements).
  • L'union de tous les intervalles est généralement proche de l'ensemble de toutes les valeurs de i (de sorte qu'il forme une partition de cet espace).
  • Les intervalles peuvent être importants (disons, i_max-i_min < 10⁶).
+1

S'il vous plaît modifier votre question et de fournir des exemples de données et les résultats souhaités. Expliquez également si les intervalles se chevauchent, sont compacts, clairsemés. . . cela pourrait affecter la solution. –

+0

Assurez-vous de [activer SQL standard] (https://cloud.google.com/bigquery/docs/reference/standard-sql/) pour utiliser ce type de fonctionnalités dans votre requête. Voir aussi le [guide de migration] (https://cloud.google.com/bigquery/docs/reference/standard-sql/migrating-from-legacy-sql). –

+0

@GordonLinoff bon point, fait. – Ted

Répondre

3

Essayez ci-dessous - BigQuery standard SQL

#standardSQL 
SELECT 
    i_min, i_max, SUM(x) AS sum_x 
FROM (
    SELECT i_min, i_max, ROW_NUMBER() OVER() AS line FROM `project.dataset.intervals` 
) AS intervals 
JOIN (SELECT i, x FROM `project.dataset.values` UNION ALL SELECT NULL, 0) AS values 
ON values.i BETWEEN intervals.i_min AND intervals.i_max OR values.i IS NULL 
GROUP BY i_min, i_max, line 
-- ORDER BY i_min 

vous pouvez jouer/test avec des données factices comme ci-dessous

#standardSQL 
WITH intervals AS (
    SELECT 1 AS i_min, 4 AS i_max UNION ALL 
    SELECT 6, 6 UNION ALL 
    SELECT 6, 6 UNION ALL 
    SELECT 6, 6 UNION ALL 
    SELECT 7, 9 UNION ALL 
    SELECT 12, 17 
), 
values AS (
    SELECT 1 AS i, 1 AS x UNION ALL 
    SELECT 2, 0 UNION ALL 
    SELECT 3, 4 UNION ALL 
    SELECT 4, 9 UNION ALL 
    SELECT 6, 7 UNION ALL 
    SELECT 7, 2 UNION ALL 
    SELECT 8, 2 UNION ALL 
    SELECT 9, 2 
) 
SELECT 
    i_min, i_max, SUM(x) AS sum_x 
FROM (SELECT i_min, i_max, ROW_NUMBER() OVER() AS line FROM intervals) AS intervals 
JOIN (SELECT i, x FROM values UNION ALL SELECT NULL, 0) AS values 
ON values.i BETWEEN intervals.i_min AND intervals.i_max OR values.i IS NULL 
GROUP BY i_min, i_max, line 
-- ORDER BY i_min 
+0

Merci encore. Par curiosité, est-ce possible dans Legacy SQL? – Ted

+0

Réalisable, mais pas uniquement une traduction un-à-un de SQL standard en raison des limitations de la clause ON dans l'héritage SQL. Mais faisable. –