ワンクリックで
db-load-csv
Import CSV data using PostgreSQL COPY with staging table and validation
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Import CSV data using PostgreSQL COPY with staging table and validation
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Execute story development with selectable automation modes to accommodate different developer preferences, skill levels, and story complexity.
Set up a Kord-aligned documentation baseline (no legacy frameworks)
Create Next Story Task methodology and workflow
Validate Next Story Task methodology and workflow
advanced-elicitation methodology and workflow
No checklists needed - this task facilitates brainstorming sessions, validation is through user interaction methodology and workflow
| name | db-load-csv |
| description | Import CSV data using PostgreSQL COPY with staging table and validation |
| agent | architect |
| subtask | false |
Import CSV data using PostgreSQL COPY with staging table and validation
Parameter:* mode (optional, default: interactive)
Purpose:* Definitive pass/fail criteria for task completion
Checklist:*
acceptance-criteria:
- [ ] Data persisted correctly; constraints respected; no orphaned data
type: acceptance-criterion
blocker: true
validation: |
Assert data persisted correctly; constraints respected; no orphaned data
error_message: "Acceptance criterion not met: Data persisted correctly; constraints respected; no orphaned data"
Strategy:* retry
Common Errors:*
Error:* Connection Failed
Error:* Query Syntax Error
Error:* Transaction Rollback
table (string): Target table namecsv_file (string): Path to CSV fileCheck file exists and table exists:
echo "Validating inputs..."
# Check CSV file exists
[ -f "{csv_file}" ] || {
echo "❌ File not found: {csv_file}"
exit 1
}
# Check table exists
psql "$SUPABASE_DB_URL" -c \
"SELECT EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_schema = 'public' AND table_name = '{table}'
);" | grep -q t || {
echo "❌ Table '{table}' not found"
exit 1
}
# Count CSV rows
ROW_COUNT=$(wc -l < "{csv_file}" | tr -d ' ')
echo "✓ CSV file: {csv_file} ($ROW_COUNT rows)"
echo "✓ Target table: {table}"
Show first few rows:
echo "CSV Preview (first 5 rows):"
head -n 5 "{csv_file}"
echo ""
echo "Continue with import? (yes/no)"
read CONFIRM
[ "$CONFIRM" = "yes" ] || { echo "Aborted"; exit 0; }
Import to staging first for validation:
echo "Creating staging table..."
psql "$SUPABASE_DB_URL" << 'EOF'
-- Create staging table with same structure as target
CREATE TEMP TABLE {table}_staging (LIKE {table} INCLUDING ALL);
-- Or if you need to define structure manually:
-- CREATE TEMP TABLE {table}_staging (
-- id TEXT,
-- name TEXT,
-- created_at TEXT
-- -- Define all columns as TEXT initially for flexible parsing
-- );
SELECT 'Staging table created' AS status;
EOF
echo "✓ Staging table ready"
Use PostgreSQL COPY command (fastest method):
echo "Loading CSV into staging table..."
# Method 1: Using psql \copy (client-side file)
psql "$SUPABASE_DB_URL" << 'EOF'
\copy {table}_staging FROM '{csv_file}' WITH (
FORMAT csv,
HEADER true,
DELIMITER ',',
QUOTE '"',
ESCAPE '"',
NULL 'NULL'
);
EOF
# Method 2: Server-side COPY (if file is on server)
# COPY {table}_staging FROM '/path/to/file.csv' WITH (FORMAT csv, HEADER true);
echo "✓ Data loaded to staging"
Run validation checks before merging:
echo "Validating staged data..."
psql "$SUPABASE_DB_URL" << 'EOF'
-- Check row count
SELECT COUNT(*) AS staged_rows FROM {table}_staging;
-- Check for NULL in required columns (example)
SELECT COUNT(*) AS null_ids
FROM {table}_staging
WHERE id IS NULL;
-- Check for duplicates (example)
SELECT id, COUNT(*) AS duplicates
FROM {table}_staging
GROUP BY id
HAVING COUNT(*) > 1;
-- Check data types can be converted (example)
SELECT
COUNT(*) FILTER (WHERE created_at::timestamptz IS NULL) AS invalid_dates
FROM {table}_staging;
-- Any validation failures?
SELECT
CASE
WHEN EXISTS (SELECT 1 FROM {table}_staging WHERE id IS NULL) THEN
'FAIL: NULL ids found'
WHEN EXISTS (SELECT 1 FROM {table}_staging GROUP BY id HAVING COUNT(*) > 1) THEN
'FAIL: Duplicate ids found'
ELSE
'PASS: All validations passed'
END AS validation_status;
EOF
echo ""
echo "Review validation results above."
echo "Continue with merge? (yes/no)"
read CONFIRM
[ "$CONFIRM" = "yes" ] || { echo "Aborted - data in staging table for review"; exit 1; }
Use UPSERT pattern for idempotency:
echo "Merging to target table..."
psql "$SUPABASE_DB_URL" << 'EOF'
BEGIN;
-- Insert new rows or update existing (idempotent)
INSERT INTO {table} (id, name, created_at, ...)
SELECT
id::uuid, -- Cast to proper types
name,
created_at::timestamptz,
...
FROM {table}_staging
ON CONFLICT (id) DO UPDATE SET
name = EXCLUDED.name,
created_at = EXCLUDED.created_at,
updated_at = NOW(); -- Update timestamp
-- Get counts
SELECT
(SELECT COUNT(*) FROM {table}) AS final_count,
(SELECT COUNT(*) FROM {table}_staging) AS imported_count;
COMMIT;
SELECT 'Import complete' AS status;
EOF
echo "✓ Data merged successfully"
Drop staging table:
echo "Cleaning up..."
psql "$SUPABASE_DB_URL" << 'EOF'
DROP TABLE IF EXISTS {table}_staging;
EOF
echo "✓ Cleanup complete"
Display import summary:
✅ CSV IMPORT COMPLETE
CSV File: {csv_file}
Target Table: {table}
Rows Imported: {count}
Duration: {duration}s
Validation:
✓ No NULL in required columns
✓ No duplicate keys
✓ All data types valid
Next steps:
- Verify data in database
- Run smoke tests if needed
- Update statistics: ANALYZE {table};
Required:*
Example:*
id,name,email,created_at
"user-1","John Doe","john@example.com","2024-01-01 00:00:00"
"user-2","Jane Smith","jane@example.com","2024-01-02 00:00:00"
For CSV files > 100MB or > 1M rows:
split -l 100000 large.csv chunk_
for file in chunk_*; do
load-csv {table} $file
done
cat large.csv | psql "$SUPABASE_DB_URL" -c \
"COPY {table} FROM STDIN WITH (FORMAT csv, HEADER true);"
Always cast from TEXT to proper types in SELECT:
SELECT
id::uuid, -- UUID
amount::numeric(10,2), -- Decimal
created_at::timestamptz, -- Timestamp
is_active::boolean, -- Boolean
metadata::jsonb -- JSON
FROM {table}_staging
Error:* invalid byte sequence for encoding "UTF8"
Fix:*
# Convert to UTF-8
iconv -f ISO-8859-1 -t UTF-8 input.csv > output.csv
Error:* unterminated CSV quoted field
Fix:* Adjust COPY parameters:
COPY table FROM 'file.csv' WITH (
DELIMITER ';', -- Change delimiter
QUOTE '''', -- Change quote character
ESCAPE '\' -- Change escape character
);
Error:* null value in column "id" violates not-null constraint
Fix:* Define NULL representation:
COPY table FROM 'file.csv' WITH (
NULL 'NULL', -- Treat literal "NULL" as NULL
-- Or NULL '' -- Treat empty strings as NULL
);
For small datasets (<1000 rows), can use regular INSERT:
// Supabase client example
const { data, error } = await supabase
.from('table')
.upsert(csvData, { onConflict: 'id' })
But COPY is 10-100x faster* for bulk loads!