Inserting data from a JavaScript array into a SQL Server table seems straightforward until you encounter special characters like quotes, commas, or brackets. Converting arrays into a SQL-compatible VALUES
list requires careful handling to avoid syntax errors or data corruption. In this article, we’ll break down a robust method to transform JavaScript arrays into SQL-ready multi-row values while preserving data integrity. We’ll also explore additional enhancements to make the solution more versatile.
The Problem
When converting a JavaScript array to a SQL VALUES
list, you need to:
- Wrap strings in single quotes (
'value'
). - Escape single quotes by doubling them (
''
). - Handle special characters like commas or brackets without breaking SQL syntax.
- Maintain the structure of the original data.
Here’s the sample JavaScript array:
const jsArray = [ [1, 'Cake', 'Special characters comma, left bracket ], right bracket ].'], [2, 'Ice cream', 'Single \'quote\' with "double" quote.'], [3, "Fudge Syrup", "Double \"quote\" with 'single' quote."] ];
The goal is to generate this SQL output:
INSERT INTO [MYTABLE] ([FIELD1], [FIELD2], [FIELD3]) VALUES (1, 'Cake', 'Special characters comma, left bracket ], right bracket ].'), (2, 'Ice cream', 'Single ''quote'' with "double" quote.'), (3, 'Fudge Syrup', 'Double "quote" with ''single'' quote.');
The Solution
Instead of manipulating the entire JSON string (which risks corrupting data), we’ll process each value individually.
Escape Single Quotes
SQL requires single quotes within strings to be escaped as ''
. We’ll write a helper function to handle this:
function processValue(value) { if (value === null || value === undefined) return 'NULL'; // Handle nulls if (typeof value === 'string') { const escaped = value.replace(/'/g, "''"); // Escape single quotes return `'${escaped}'`; } return value; // Numbers or booleans }
Convert Rows to SQL Syntax
Map each array row to a SQL-compatible string:
function convertToSQLValues(jsArray) { return jsArray.map(row => { const processedRow = row.map(processValue).join(', '); return `(${processedRow})`; }).join(',\n '); }
Generate the Full INSERT Statement
Combine everything into a complete SQL query:
function generateInsertStatement(table, fields, jsArray) { const values = convertToSQLValues(jsArray); return `INSERT INTO [${table}] (${fields.map(f => `[${f}]`).join(', ')})\nVALUES\n ${values};`; } // Usage: const sql = generateInsertStatement('MYTABLE', ['FIELD1', 'FIELD2', 'FIELD3'], jsArray); console.log(sql);
Handling Edge Cases
- Null Values: TheÂ
processValue
 function already returnsÂNULL
 forÂnull
 orÂundefined
 values. - Dates: ConvertÂ
Date
 objects to SQL-friendly strings:
if (value instanceof Date) {
return `'${value.toISOString().slice(0, 19).replace('T', ' ')}'`; // YYYY-MM-DD HH:MM:SS
}
Booleans: Convert true
/false
 to 1
/0
 for SQL Server:
if (typeof value === 'boolean') return value ? 1 : 0;
Enhanced Functionality
Batch Insertion Limits
SQL Server restricts batches to ~1000 rows. Split large arrays into chunks:
function chunkArray(arr, size) { return arr.length > size ? [arr.slice(0, size), ...chunkArray(arr.slice(size), size)] : [arr]; } const batches = chunkArray(jsArray, 1000); batches.forEach(batch => generateInsertStatement('MYTABLE', ['FIELD1', 'FIELD2', 'FIELD3'], batch));
Parameterized Queries (Safer Alternative)
Avoid SQL injection by using parameterized queries with libraries like mssql
:
const { Request } = require('mssql'); async function bulkInsert(pool, table, rows) { const request = new Request(pool); rows.forEach((row, idx) => { request.input(`field1_${idx}`, row[0]); request.input(`field2_${idx}`, row[1]); request.input(`field3_${idx}`, row[2]); }); await request.query(`INSERT INTO ${table} VALUES ${rows.map((_, i) => `(@field1_${i}, @field2_${i}, @field3_${i})`).join(', ')}`); }
Final Thoughts
Manually converting JavaScript arrays to SQL VALUES
lists works for small datasets, but always prioritize parameterized queries or ORM tools (like Sequelize) for security and scalability. If you must generate raw SQL, ensure thorough testing for edge cases like Unicode characters or emojis. The key takeaway: process each value individually instead of relying on regex hacks, and always escape user-generated content!