func CreateOrUpdate(schema bigquery.Schema, project, dataset, table, partField string) error {
	name := project + "." + dataset + "." + table
	pdt, err := bqx.ParsePDT(name)
	rtx.Must(err, "ParsePDT")
	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
	defer cancel()
	client, err := bigquery.NewClient(ctx, pdt.Project)
	rtx.Must(err, "NewClient")
	err = pdt.UpdateTable(ctx, client, schema)
	if err == nil {
		log.Println("Successfully updated", pdt)
		return nil
	}
	log.Println("UpdateTable failed:", err)
	apiErr, ok := err.(*googleapi.Error)
	if !ok || apiErr.Code != 404 {
	}
	partitioning := &bigquery.TimePartitioning{
		Field: partField,
	}
	err = pdt.CreateTable(ctx, client, schema, "description", partitioning, nil)
	if err == nil {
		log.Println("Successfully created", pdt)
		return nil
	}
	log.Println("Create failed:", err)
	return err
}
CreateOrUpdate will update or create a table from the given schema.
package main
import (
	"context"
	"flag"
	"log"
	"os"
	"strings"
	"time"
	"cloud.google.com/go/bigquery"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/iterator"
	"github.com/m-lab/go/cloud/bqx"
	"github.com/m-lab/go/flagx"
	"github.com/m-lab/go/rtx"
	"github.com/m-lab/etl/schema"
)
func CreateOrUpdateTCPInfo(project string, dataset string, table string) error {
	row := schema.TCPRow{}
	schema, err := row.Schema()
	rtx.Must(err, "TCPRow.Schema")
	if dataset == "batch" {
		updateTemplateTables(schema, project, dataset, table, "")
	}
	return CreateOrUpdate(schema, project, dataset, table, "")
}
func CreateOrUpdatePT(project string, dataset string, table string) error {
	row := schema.PTTest{}
	schema, err := row.Schema()
	rtx.Must(err, "PTTest.Schema")
	if dataset == "batch" {
		updateTemplateTables(schema, project, dataset, table, "")
	}
	return CreateOrUpdate(schema, project, dataset, table, "")
}
func CreateOrUpdateSS(project string, dataset string, table string) error {
	row := schema.SS{}
	schema, err := row.Schema()
	rtx.Must(err, "SS.Schema")
	if dataset == "batch" {
		updateTemplateTables(schema, project, dataset, table, "")
	}
	return CreateOrUpdate(schema, project, dataset, table, "")
}
func CreateOrUpdateNDTWeb100(project string, dataset string, table string) error {
	row := schema.NDTWeb100{}
	schema, err := row.Schema()
	rtx.Must(err, "NDTWeb100.Schema")
	if dataset == "batch" {
		updateTemplateTables(schema, project, dataset, table, "")
	}
	return CreateOrUpdate(schema, project, dataset, table, "")
}
func CreateOrUpdateNDT5ResultRow(project string, dataset string, table string) error {
	row := schema.NDT5ResultRow{}
	schema, err := row.Schema()
	rtx.Must(err, "NDT5ResultRow.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "")
}
func CreateOrUpdateNDT5ResultRowStandardColumns(project string, dataset string, table string) error {
	row := schema.NDT5ResultRowStandardColumns{}
	schema, err := row.Schema()
	rtx.Must(err, "NDT5ResultRowStandardColumns.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "")
}
func CreateOrUpdateNDT7ResultRow(project string, dataset string, table string) error {
	row := schema.NDT7ResultRow{}
	schema, err := row.Schema()
	rtx.Must(err, "NDT7ResultRow.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "Date")
}
func CreateOrUpdateAnnotationRow(project string, dataset string, table string) error {
	row := schema.AnnotationRow{}
	schema, err := row.Schema()
	rtx.Must(err, "Annotation.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "Date")
}
func CreateOrUpdateSwitchStats(project string, dataset string, table string) error {
	row := schema.SwitchStats{}
	schema, err := row.Schema()
	rtx.Must(err, "SwitchStats.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "")
}
func CreateOrUpdatePCAPRow(project string, dataset string, table string) error {
	row := schema.PCAPRow{}
	schema, err := row.Schema()
	rtx.Must(err, "PCAPRow.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "Date")
}
func CreateOrUpdateHopAnnotation1Row(project string, dataset string, table string) error {
	row := schema.HopAnnotation1Row{}
	schema, err := row.Schema()
	rtx.Must(err, "HopAnnotation1Row.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "Date")
}
func CreateOrUpdateScamper1Row(project string, dataset string, table string) error {
	row := schema.Scamper1Row{}
	schema, err := row.Schema()
	rtx.Must(err, "Scamper1Row.Schema")
	return CreateOrUpdate(schema, project, dataset, table, "Date")
}
func listTemplateTables(project, dataset, table string) ([]string, error) {
	tables := []string{}
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
	defer cancel()
	client, err := bigquery.NewClient(ctx, project)
	if err != nil {
		return nil, err
	}
	it := client.Dataset(dataset).Tables(ctx)
	for {
		t, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		if strings.HasPrefix(t.TableID, table+"_") {
			tables = append(tables, t.TableID)
		}
	}
	return tables, nil
}
func updateTemplateTables(schema bigquery.Schema, project, dataset, table, partField string) error {
	tables, err := listTemplateTables(project, dataset, table)
	if err != nil {
		return err
	}
	for i := range tables {
		err = CreateOrUpdate(schema, project, dataset, tables[i], partField)
		if err != nil {
			return err
		}
	}
	return nil
}