About oci-billing-query
This skill defines a workflow for analysts querying and interpreting Oracle Cloud Infrastructure billing data. It uses DuckDB to query a StarRocks database, requires a date partition filter and CSV export before analysis, and reports costs in USD by default.
Key features
- 01Query billing data through DuckDB
- 02Filter partitions by cost_date
- 03Export query results to CSV first
- 04Analyze by service, customer, tenant, or region
- 05Review time trends and billing corrections
Use cases
- 01Summarize OCI costs for a date range
- 02Compare billing by service or customer
- 03Inspect cost distribution by tenant and region
- 04Investigate cost trends or correction records
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ agw-sales-ops/ skills --skill oci-billing-queryAfter installing, type/oci-billing-queryin Claude Code to confirm it loaded.
Details
From the project READMEYou 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
- 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. - ALL queries MUST include a
cost_datepartition filter — this is a partitioned table; queries withoutcost_datewill be extremely slow. - Never execute the CREATE SECRET / ATTACH statements — these are pre-configured in
~/.duckdbrcand loaded automatically. - Always validate the date range with the user if not explicitly specified — default to the current month if the user doesn't specify.
- All monetary fields are USD — report totals, averages, and trends in USD by default.
Prerequisites
Step 1: Install DuckDB (if not installed)
curl https://install.duckdb.org | sh
After installation, DuckDB binary is at ~/.duckdb/cli/latest/duckdb. Add to PATH if needed:
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:
cat ~/.duckdbrc
Step 3: Verify connection
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:
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:
# 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:
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:
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:
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):
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:
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:
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:
- Clarify the date range — if the user doesn't specify, ask or default to the current month.
- Build the SQL — always include
cost_datefilter, always wrap inCOPY (... ) TO 'filename.csv'. - Execute via DuckDB — run
duckdb -c "..."in bash. - Read the CSV — use
head,wc -l, orcatto inspect the output. - Analyze and present — summarize findings, highlight patterns, flag anomalies.
- Present the CSV file — use
mcp__cowork__present_filesto 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
LIMITto aggregation queries to keep CSV files manageable. - Use
yearandmonthfields for monthly/annual rollups instead of parsingcost_date. customer_namesupportsLIKEfor fuzzy matching — useful when the exact name is unknown.- Always check
line_item_is_correctionif cost numbers look unexpected — corrections may inflate or deflate totals. - The
cost_list_price_costfield is the primary cost metric for most analyses.