5

I am use nodejs npm package sql I currently have an array of product skus like so..

var skus = ['product1', 'product2', 'product3'];

My sql store in a file as follows...

SELECT *
FROM stock AS s
WHERE s.sku IN (@skus)

Then I also have my prepared statement code as follows..

var connection = new sql.Connection(config, function(err) {
        var ps = new sql.PreparedStatement(connection);
        //Add params
        if(params != undefined){
            for(var key in params){
                ps.input(key, sql.VarChar(200));
            }
        }
        ps.prepare(sqlstatement, function(err) {
            ps.execute(params, function(err, data) {
                callback(null, data);
                ps.unprepare(function(err) {
                });
            });
        });
    });
}

skus is contained correctly within the params object as the statement works fine when I am using it for simple WHERE X = @YI am just struggling with how I need pass the array of skus to allow them to work in the prepared statement.

I am amend the string using split and join to comma seperate them etc etc but I can't get these methods to work.

I assumed that I would need the param string to look like the following 'product1','product2','product3'.

would be also useful if someone could shed some light on how to debug the completed prepared statement so I can see what is actually being queried to SQL (with params inplace)

Many thanks in advance!

1

2 Answers 2

6

It appears that the sql object (i.e. the mssql module) has no attribute to handle arrays of anything. Moreover, specifying a scalar type in the call to ps.input similarly does not work.

The next best thing is to build keys for your array of parameters into your sql statement itself:

var connection = new sql.Connection(config, function(err) {
        var ps = new sql.PreparedStatement(connection);
        // Construct an object of parameters, using arbitrary keys
        var paramsObj = params.reduce((obj, val, idx) => {
            obj[`id${idx}`] = val;
            ps.input(`id${idx}`, sql.VarChar(200));
            return obj;
        }, {});
        // Manually insert the params' arbitrary keys into the statement
        var stmt = 'select * from table where id in (' + Object.keys(paramsObj).map((o) => {return '@'+o}).join(',') + ')';
        ps.prepare(stmt, function(err) {
            ps.execute(paramsObj, function(err, data) {
                callback(null, data);
                ps.unprepare(function(err) {
                });
            });
        });
    });
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for clarifying, i think I ended generating comma separated strings.
who would have thought that a hacky solution would be the result.. they should definitely have proper support for this upstream in mssql..
0

in case other people like me come across this, here is a little helper function:


let nonce = 0;

export function inputList(req: sql.Request, data: Array<any>, type: (() => sql.ISqlType) | sql.ISqlType): string {
    const out = [];
    nonce++;
    nonce %= 1e6;
    const name = nonce.toString(36);

    // classic for loop should be faster but i'm lazy. do the optimization yourself.
    data.forEach((value, index) => {
        const key = `_${name}_${index.toString(36)}`;
        out.push(`@${key}`);
        if (type) req.input(key, type, value);
        else req.input(key, value);
    });

    return `(${out.join(",")})`;
};

// example usage. don't take it as best practice:
export async function getDocTypes(docTypes: Array<string>) {
    const out = {};
    const req = pool.request();
    const res = await req.query(`
        SELECT
            [dt].[kue_dokuart] as [type],
            [dt].[langtext] as [name]
        FROM
            [dbo].[dokuart_langtexte] as [dt]
        WHERE
            [dt].[kue_dokuart] IN ${inputList(req, docTypes, sql.NVarChar)}
        AND
            [dt].[sprache] = '049'
    `);

    res.recordset.forEach(row => {
        out[row.type] = row.name;
    });

    return out;
};
> await getDocTypes(["APERS", "DPERS"])
{APERS: 'Personalakte', DPERS: 'Personaldokumente'}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.