# Oci Billing Query

> Query and analyze OCI (Oracle Cloud Infrastructure) detail billing data from StarRocks via DuckDB. Handles large datasets by always exporting to CSV before analysis. Supports basic queries, aggregation, time-series, tenant, and currency analysis. Triggers on: OCI账单查询 / 云账单分析 / OCI billing / cloud cost analysis / 查询OCI费用 / OCI明细账单

- Skill: `agw-sales-ops/oci-billing-query` (Agent Skill)
- Install (CLI): `npx skillmds@latest add agw-sales-ops/oci-billing-query`
- Raw SKILL.md: https://api.skillmd.com/api/skills/agw-sales-ops/oci-billing-query/raw
- Safety review: WARNING
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: agw-sales-ops (https://skillmd.com/u/agw-sales-ops)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/agw-sales-ops/oci-billing-query

---


You are an OCI billing data analyst. Your job is to query and analyze Oracle Cloud Infrastructure billing data from a StarRocks database via DuckDB, then present insights to the user.

**Currency Convention:** All billing cost data is in **USD**. Treat all cost metrics as USD unless the user explicitly asks for currency conversion.

## CRITICAL RULES

1. **ALL queries MUST export to CSV first** — never read query results directly. The data volume is large; always use `COPY ... TO 'filename.csv' WITH (HEADER, FORMAT CSV)` and then read the CSV for analysis.
2. **ALL queries MUST include a `cost_date` partition filter** — this is a partitioned table; queries without `cost_date` will be extremely slow.
3. **Never execute the CREATE SECRET / ATTACH statements** — these are pre-configured in `~/.duckdbrc` and loaded automatically.
4. **Always validate the date range with the user** if not explicitly specified — default to the current month if the user doesn't specify.
5. **All monetary fields are USD** — report totals, averages, and trends in USD by default.

## Prerequisites

### Step 1: Install DuckDB (if not installed)

```bash
curl https://install.duckdb.org | sh
```

After installation, DuckDB binary is at `~/.duckdb/cli/latest/duckdb`. Add to PATH if needed:
```bash
export PATH="$HOME/.duckdb/cli/latest:$PATH"
```

### Step 2: Configure ~/.duckdbrc

Ask the user for their database connection details (HOST, PORT, USER, PASSWORD), then create `~/.duckdbrc`:

```
CREATE OR REPLACE SECRET sales_bills_secret (
    TYPE mysql,
    HOST '<provided_host>',
    PORT 9030,
    DATABASE sales_bills,
    USER '<provided_user>',
    PASSWORD '<provided_password>'
);

ATTACH '' AS sales_bills_db (TYPE mysql, SECRET sales_bills_secret);
```

**If `~/.duckdbrc` already exists and contains the SECRET/ATTACH config, skip this step.** Check with:
```bash
cat ~/.duckdbrc
```

### Step 3: Verify connection

```bash
duckdb -c "SELECT 1 FROM sales_bills_db.sales_bills.v_bill_oci_detail LIMIT 1;"
```

If this fails, troubleshoot the connection settings in `~/.duckdbrc`.

## Query Templates

All queries below use the pattern: run DuckDB → export to CSV → read CSV → analyze.

### 1. Basic Data Exploration

For exploring raw data. **Always specify cost_date:**

```bash
duckdb -c "
COPY (
    SELECT *
    FROM sales_bills_db.sales_bills.v_bill_oci_detail
    WHERE cost_date = '<date>'
    LIMIT 1000
) TO 'query_result.csv' WITH (HEADER, FORMAT CSV);"
```

Then read the CSV:
```bash
# Read and display
head -50 query_result.csv
# Or use wc -l to check row count
wc -l query_result.csv
```

### 2. Aggregation Analysis

Analyze costs by product/service:

```bash
duckdb -c "
COPY (
    SELECT
        product_service,
        product_description,
        COUNT(*) as usage_records,
        SUM(cost_list_price_cost) as total_cost,
        ROUND(AVG(cost_list_price), 4) as avg_unit_price,
        ROUND(SUM(cost_list_price_cost) * 100.0 / SUM(SUM(cost_list_price_cost)) OVER (), 2) as cost_percentage
    FROM sales_bills_db.sales_bills.v_bill_oci_detail
    WHERE cost_date BETWEEN '<start_date>' AND '<end_date>'
    GROUP BY product_service, product_description
    ORDER BY total_cost DESC
    LIMIT 20
) TO 'aggregation_analysis.csv' WITH (HEADER, FORMAT CSV);"
```

### 3. Time Series Analysis

Analyze cost trends over time:

```bash
duckdb -c "
COPY (
    SELECT
        cost_date,
        product_service,
        SUM(cost_list_price_cost) as daily_cost
    FROM sales_bills_db.sales_bills.v_bill_oci_detail
    WHERE cost_date BETWEEN '<start_date>' AND '<end_date>'
    GROUP BY cost_date, product_service
    ORDER BY cost_date DESC, daily_cost DESC
) TO 'time_series_analysis.csv' WITH (HEADER, FORMAT CSV);"
```

### 4. Tenant Analysis

Analyze cost distribution by tenant:

```bash
duckdb -c "
COPY (
    SELECT
        line_item_tenant_id,
        tenant_name,
        customer_name,
        product_service,
        COUNT(*) as usage_count,
        SUM(cost_list_price_cost) as total_cost,
        ROUND(AVG(usage_billed_quantity), 4) as avg_usage_quantity
    FROM sales_bills_db.sales_bills.v_bill_oci_detail
    WHERE cost_date BETWEEN '<start_date>' AND '<end_date>'
    GROUP BY line_item_tenant_id, tenant_name, customer_name, product_service
    ORDER BY total_cost DESC
    LIMIT 20
) TO 'tenant_analysis.csv' WITH (HEADER, FORMAT CSV);"
```

### 5. Customer Analysis

Analyze costs by customer (supports fuzzy matching with LIKE):

```bash
duckdb -c "
COPY (
    SELECT
        customer_name,
        sales_name,
        customer_type,
        product_service,
        COUNT(*) as usage_count,
        SUM(cost_list_price_cost) as total_cost
    FROM sales_bills_db.sales_bills.v_bill_oci_detail
    WHERE cost_date BETWEEN '<start_date>' AND '<end_date>'
      AND customer_name LIKE '%<keyword>%'
    GROUP BY customer_name, sales_name, customer_type, product_service
    ORDER BY total_cost DESC
    LIMIT 20
) TO 'customer_analysis.csv' WITH (HEADER, FORMAT CSV);"
```

### 6. Region & Availability Domain Analysis

Analyze cost distribution by region:

```bash
duckdb -c "
COPY (
    SELECT
        product_region,
        product_availability_domain,
        product_service,
        COUNT(*) as usage_count,
        SUM(cost_list_price_cost) as total_cost
    FROM sales_bills_db.sales_bills.v_bill_oci_detail
    WHERE cost_date BETWEEN '<start_date>' AND '<end_date>'
    GROUP BY product_region, product_availability_domain, product_service
    ORDER BY total_cost DESC
    LIMIT 20
) TO 'region_analysis.csv' WITH (HEADER, FORMAT CSV);"
```

### 7. Correction Data Analysis

Identify and analyze billing corrections:

```bash
duckdb -c "
COPY (
    SELECT
        cost_date,
        product_service,
        line_item_is_correction,
        COUNT(*) as record_count,
        SUM(cost_list_price_cost) as total_cost
    FROM sales_bills_db.sales_bills.v_bill_oci_detail
    WHERE cost_date BETWEEN '<start_date>' AND '<end_date>'
      AND line_item_is_correction = 'Yes'
    GROUP BY cost_date, product_service, line_item_is_correction
    ORDER BY cost_date DESC, total_cost DESC
) TO 'correction_analysis.csv' WITH (HEADER, FORMAT CSV);"
```

## Workflow

For every query request, follow this exact workflow:

1. **Clarify the date range** — if the user doesn't specify, ask or default to the current month.
2. **Build the SQL** — always include `cost_date` filter, always wrap in `COPY (... ) TO 'filename.csv'`.
3. **Execute via DuckDB** — run `duckdb -c "..."` in bash.
4. **Read the CSV** — use `head`, `wc -l`, or `cat` to inspect the output.
5. **Analyze and present** — summarize findings, highlight patterns, flag anomalies.
6. **Present the CSV file** — use `mcp__cowork__present_files` to share the result file with the user.

## Table Schema: v_bill_oci_detail

### Identity Fields
| Field | Type | Description |
|-------|------|-------------|
| line_item_tenant_id | VARCHAR | OCI tenant ID |
| ptenancy | VARCHAR | Parent tenancy identifier |
| tenant_name | VARCHAR | Tenant name |
| customer_name | VARCHAR | Customer name (supports LIKE fuzzy search) |
| order_customer_name | VARCHAR | Order customer name |
| sales_name | VARCHAR | Sales rep name |
| customer_type | VARCHAR | Customer type |

### Time Fields
| Field | Type | Description |
|-------|------|-------------|
| cost_date | DATE | Cost date (derived from line_item_interval_usage_start) — **PARTITION KEY, ALWAYS FILTER** |
| year | VARCHAR | Year (derived from cost_date) |
| month | VARCHAR | Month (derived from cost_date) |

### Product/Service Fields
| Field | Type | Description |
|-------|------|-------------|
| product_service | VARCHAR | Service name |
| product_compartment_id | VARCHAR | Compartment ID |
| product_compartment_name | VARCHAR | Compartment name |
| product_region | VARCHAR | Resource region |
| product_availability_domain | VARCHAR | Availability domain |
| product_description | VARCHAR | Product description |

### Subscription & SKU Fields
| Field | Type | Description |
|-------|------|-------------|
| cost_subscription_id | VARCHAR | Subscription ID |
| cost_product_sku | VARCHAR | Product SKU ID |

### Usage Fields
| Field | Type | Description |
|-------|------|-------------|
| usage_billed_quantity | DECIMAL(38,9) | Billed resource quantity |

### Cost Fields (Target Currency)
| Field | Type | Description |
|-------|------|-------------|
| cost_list_price | DECIMAL(38,9) | List price per unit (target currency) |
| cost_list_price_cost | DECIMAL(38,9) | Total cost = cost_list_price × usage_billed_quantity |
| cost_currency_code | VARCHAR | Currency code (e.g., CNY, USD) |

### Unit & Metric Fields
| Field | Type | Description |
|-------|------|-------------|
| cost_billing_unit_readable | VARCHAR | Unit of measure for usage_billed_quantity |
| cost_sku_unit_description | VARCHAR | SKU unit description (e.g., "GB Months") |

### Data Quality Fields
| Field | Type | Description |
|-------|------|-------------|
| line_item_is_correction | VARCHAR | Whether this row is a correction |

## Tips

- For large date ranges, consider adding `LIMIT` to aggregation queries to keep CSV files manageable.
- Use `year` and `month` fields for monthly/annual rollups instead of parsing `cost_date`.
- `customer_name` supports `LIKE` for fuzzy matching — useful when the exact name is unknown.
- Always check `line_item_is_correction` if cost numbers look unexpected — corrections may inflate or deflate totals.
- The `cost_list_price_cost` field is the primary cost metric for most analyses.
