MYSQL SQL拼接工具

最近用到node+express+mysql开发后端业务,但是sql的拼写相当麻烦,特别是查询条件的拼接,故书写了如下工具,方便sql生成。

当查询条件值为null时,一般不需要该条件。即sql需要动态生成。

工具文件

sqlUtil.ts

/*查询字段 */
interface fieldProps { //distinct name as aname
    expression: any;    //字段表达式,对应数据库字段,例如distinct name
    valueField?: string;  //数据对应的字段
    alias?: string;      //别名
}

/*where条件 */
interface whereProps {   //where name=? and 
    expression: string; //条件表达式,例如name=?
    valueField?: string;    //数据对应字段
    relation?: string;   //关系,and、or
}

/*排序 */
interface orderByProps {
    field: string; //排序字段
    direction?: string;   //排序方向,desc/asc
}

/* limit */
interface limitProps {
    begin: number;   //起始位置
    end: number;     //结束位置
}


interface sqlOptionsProps {
    type: string;
    fields?: null | fieldProps[];
    tableName: string;
    where?: null | whereProps[];
    orderBy?: null | orderByProps[];
    limit?: null | limitProps;
}


/**
 * 
 * @param type //sql类型,select、insert、update、delete
 * @param fields //查询字段,默认为空,查询所有字段
 * @param tableName //表名
 * @param where //where条件,默认为空,即无条件
 * @param orderBy //排序条件,默认为空,即不排序
 * @param limit   //分页参数,存在时默认查询前10条数据
 */
const getSqlStr = (
    type: string,
    fields: null | fieldProps[] = [],
    tableName: string,
    where: null | whereProps[] = [],
    orderBy: null | orderByProps[] = [],
    limit: null | limitProps = { begin: 0, end: 9 }
) => {
    let sql = "";
    //表名
    if (!tableName) {
        console.log("表名不能为空!")
    }
    switch (type) {
        case "select":
        case "SELECT":
            //sql类型
            sql += "SELECT ";
            //查询字段
            if (fields && fields.length > 0) {
                for (let field of fields) {
                    if (field.expression) {
                        sql += field.expression;
                    }
                    if (field.alias) {
                        sql += " AS " + field.alias
                    }

                    sql += ",";
                }
                //去掉末尾的,
                sql = sql.substring(0, sql.length - 1);
            } else {
                sql += "*";
            }

            sql += " FROM " + tableName;

            //where条件
            if (where && where.length > 0) {
                let whereStr = joinWhere(where);
                sql += whereStr
            }

            //order by
            if (orderBy && orderBy.length) {
                sql += " ORDER BY ";
                for (let i = 0; i < orderBy.length; i++) {
                    let order = orderBy[i];
                    let direction = order.direction ? order.direction : "ASC";
                    sql += `${order.field} ${direction}`;
                    //添加逗号
                    if (i != orderBy.length - 1) {
                        sql += ","
                    }
                }
            }

            //limit
            if (limit) {
                sql += ` limit ${limit.begin},${limit.end}`;
            }

            break;

        case "insert":
        case "INSERT":
            sql += `INSERT INTO ${tableName}(`;
            if (fields && fields.length > 0) {
                //设置新增字段
                for (let i = 0; i < fields.length; i++) {
                    let field = fields[i];
                    sql += `${field.expression}`
                    if (i != fields.length - 1) {
                        sql += ","
                    } else {
                        sql += ")"
                    }
                }

                //设置新增值,新增和编辑的值用?代替,使用mysql的传参方式传入,
                //因为参数入库涉及到参数类型校验,例如日期格式,前端检验相当麻烦,所以直接交由mysql的Api处理
                sql += " VALUE(";
                for (let i = 0; i < fields.length; i++) {
                    let field = fields[i];
                    sql += "?"
                    if (i != fields.length - 1) {
                        sql += ","
                    } else {
                        sql += ")"
                    }
                }
            } else {
                console.log("新增表字段不能为空!")
            }

            break;

        case "update":
        case "UPDATE":
            sql += `UPDATE ${tableName} SET `;
            if (fields && fields.length > 0) {
                for (let i = 0; i < fields.length; i++) {
                    let field = fields[i];
                    sql += `${field.expression}=?`
                    if (i != fields.length - 1) {
                        sql += ","
                    }
                }
            } else {
                console.log("修改表字段不能为空!")
            }

            //where条件
            if (where && where.length > 0) {
                let whereStr = joinWhere(where);
                sql += whereStr
            }
            break;
        case "delete":
        case "DELETE":
            sql += `DELETE FROM ${tableName}`;
            if (where && where.length > 0) {
                let whereStr = joinWhere(where);
                sql += whereStr
            }
            break;
    }
    return sql;
}

/**
 * 生成可执行sql和sql所需要的参数
 * @param sqlOptions 
 * @param resquestParams 
 */
const sqlJoin = (sqlOptions: sqlOptionsProps, resquestParams: any) => {
    let type = sqlOptions.type || "select";
    let fields: any = sqlOptions.fields;
    let tableName = sqlOptions.tableName;
    let where: any = sqlOptions.where;
    let orderBy = sqlOptions.orderBy;
    let limit = sqlOptions.limit;
    let whereValue = getWhereValue(where, resquestParams);
    let filedsParams = getFiledsParams(type, fields, resquestParams);
    let sqlStr = getSqlStr(type, fields, tableName, whereValue.whereArr, orderBy, limit);
    let paramsArr = filedsParams.concat(whereValue.paramsArr);
    return {
        sqlStr,
        paramsArr
    }
}


/**
 * 拼接wehre条件,最后一个条件的关系将会被舍弃,默认如果未配置关系则视为AND
 * @param where 
 */
const joinWhere = (where: whereProps[]) => {
    let whereStr = "";
    //where条件
    whereStr += " WHERE ";
    for (let i = 0; i < where.length; i++) {
        let wh = where[i]
        whereStr += wh.expression;
        if (i != where.length - 1) {
            if (wh.relation && wh.relation != "") {
                whereStr += " " + wh.relation + " ";
            } else {
                whereStr += " AND ";
            }

        }
    }
    return whereStr;
}

/**
 * 获取where条件和其对应的参数,返回一个对象,whereArr为条件,paramsArr为条件值,一一对应
 * @param whereList //手动配置的可选条件
 * @param searchObj //条件值对象
 */
const getWhereValue = (whereList: whereProps[], searchObj: any) => {
    let whereArr = [];  //条件数组
    let paramsArr = []; //条件值数组,用于替换问号数据
    if (searchObj && whereList && whereList.length > 0) {
        for (let where of whereList) {
            if (where.valueField) {
                let value = searchObj[where.valueField];
                let isEmpty = isEmptyFilter(value, true);
                if (!isEmpty) {
                    whereArr.push(where);
                    paramsArr.push(value);
                }
            }
        }
    }
    return {
        whereArr,
        paramsArr
    };
}


const getFiledsParams = (type: string, fileds: fieldProps[], resquestParams: any) => {
    let filedsParams: any[] = [];
    let typeLower = type.toLowerCase();
    //查询和删除不需要字段参数,只有where参数
    if (typeLower === 'select' || typeLower === 'delete') {
        return filedsParams;
    }
    //字段拼接参数
    if (fileds && fileds.length > 0) {
        for (let filed of fileds) {
            if (filed.valueField) {
                //数据库不接收undefined
                let param = resquestParams[filed.valueField] || null;
                filedsParams.push(param);
            }
        }
    }

    return filedsParams;
}

/**
 * 校验数据是否为空
 * @param value             //数据
 * @param vaildEmptyStr     //是否对空字符串进行校验
 */
const isEmptyFilter = (value: any, vaildEmptyStr: boolean = false) => {
    let valueType = Object.prototype.toString.call(value);
    switch (valueType) {
        case "[object Null]":
        case "[object Undefined]":
            return true;
        case "[object String]":
            if (vaildEmptyStr && value === "") {
                return true;
            }
            return false;
        default:
            return false;
    }
}

export default {
    sqlJoin
}; 

本拼接工具只适用于单表操作,多表操作请自行在单表操作的基础上封装。

用法

SELECT

let options = {
        type: "select",
        fields: null,
        tableName: "tableA",
        where: [
            { expression: "name=?", valueField: "name", relation: "AND" },
            { expression: "age=?", valueField: "age", relation: "AND" },
        ],
        orderBy: null,
        limit: { begin: 0, end: 9 }
    }
    let params = {
        name:"张珊",
        age:""
    }
    let sql = sqlUtil.sqlJoin(options,params)
    console.log(sql)

{“sqlStr”:“SELECT * FROM tableA WHERE name=? limit 0,9”,“paramsArr”:[“张珊”]}

INSERT

let options = {
        type: "insert",
        fields: [
            { expression: "name", valueField: "name" },
            { expression: "age", valueField: "age" },
        ],
        tableName: "tableA"
    }
    let params = {
        name: "张珊",
        age: "27"
    }
    let sql = sqlUtil.sqlJoin(options, params)
    console.log(sql)

{“sqlStr”:“INSERT INTO tableA(name,age) VALUE(?,?)”,“paramsArr”:[“张珊”,“27”]}

修改

let options = {
        type: "update",
        fields: [
            { expression: "name", valueField: "name" },
            { expression: "age", valueField: "age" },
        ],
        tableName: "tableA",
        where: [
            { expression: "id=?", valueField: "id" }
        ]
    }
    let params = {
        id: 1,
        name: "张珊",
        age: "27"
    }
    let sql = sqlUtil.sqlJoin(options, params)
    console.log(sql)

{“sqlStr”:“UPDATE tableA SET name=?,age=? WHERE id=?”,“paramsArr”:[“张珊”,“27”,1]}

删除

let options = {
        type: "delete",
        fields:null,
        tableName: "tableA",
        where: [
            { expression: "id=?", valueField: "id" }
        ]
    }
    let params = {
        id: 1,
        name: "张珊",
        age: "27"
    }
    let sql = sqlUtil.sqlJoin(options, params)
    console.log(sql)

{“sqlStr”:“DELETE FROM tableA WHERE id=?”,“paramsArr”:[1]}

Express支持Typescript

1.创建Express根目录

新建server目录作为服务端根目录。

2.安装express依赖

npm i -g express 

可通过npx express-generator脚手架生成express项目结构

3.安装ts依赖

@types/express是express对ts的支持依赖
@types/node是node对ts的支持依赖

npm install @types/node --save
npm install @types/express --save-dev

4.ts编译配置

默认情况下,node是遵循CommonJS规范的,且不不能识别ts文件,所以需要将ts文件转化为可识别的es文件。

在server目录下添加tsconfig.json文件,内容如下:

{
    "compilerOptions": {
        "target": "es5",                //编译的语言版本
        "module": "commonjs",           //生成代码的规范标准
        "allowJs":true,                 //编译时允许有js
        "emitDecoratorMetadata": true,  //为注解声明加上元数据类型
        "experimentalDecorators": true, //允许注解语法
        "sourceMap":true,               //生成js的同时,生成对应的map文件
        "removeComments":true,          //编译时去除注释
        "esModuleInterop":true,         //允许export=导出,由import from 导入
        "allowSyntheticDefaultImports":true,    //允许引入没有默认导出的模块
        "outDir": "public",            //编译后的文件输出目录
        "lib": [                       //声明ts需引入的库
            "es6"
        ]
    },
    "exclude": [                       //排除内容
        "node_modules"
    ]
}

npm i
npm start
启动后,可在http://localhost:3000/下查看页面是否可访问,是否保错

项目参考地址

https://github.com/windSandEye/personal-homepage.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
游标动态SQL拼接是一种将游标和动态SQL语句结合使用的技术,可以根据需要动态生成SQL语句,从而实现更加灵活的数据库操作。具体实现步骤如下: 1. 定义游标:使用DECLARE CURSOR语句定义游标,指定需要遍历的数据集合。 2. 定义变量:使用DECLARE语句定义需要使用的变量,例如存储表名、SQL语句等。 3. 打开游标:使用OPEN语句打开游标,开始遍历数据集合。 4. 循环遍历:使用FETCH语句循环遍历游标,获取每一条记录。 5. 动态SQL拼接:根据需要动态拼接SQL语句,可以使用CONCAT函数将多个字符串拼接在一起。 6. 执行SQL语句:使用PREPARE语句将动态生成的SQL语句准备好,然后使用EXECUTE语句执行SQL语句。 7. 关闭游标:使用CLOSE语句关闭游标,释放资源。 8. 提交事务:使用COMMIT语句提交事务,确保数据操作的一致性。 下面是一个示例存储过程,演示了如何使用游标动态SQL拼接来清空数据库中的所有表(除了以t_开头的表和comp表): ```mysql CREATE PROCEDURE `CleanDb`() BEGIN DECLARE nodata int DEFAULT 0; DECLARE tnm VARCHAR(128); DECLARE cnt int DEFAULT 0; DECLARE sql_str VARCHAR(2000); DECLARE cur_tbls CURSOR FOR SELECT DISTINCT table_name from information_schema.`TABLES` WHERE TABLE_schema = 'db_dl' ORDER BY table_name; DECLARE CONTINUE handler for not found set nodata = 1; OPEN cur_tbls; ll:LOOP FETCH cur_tbls INTO tnm; IF nodata = 1 THEN LEAVE ll; END IF; SET sql_str = ''; IF tnm NOT LIKE 't_%' AND tnm <> 'comp' THEN SET sql_str = CONCAT('DROP TABLE ',tnm,';'); SET @sql = sql_str; PREPARE s1 FROM @sql; EXECUTE s1; DEALLOCATE PREPARE s1; END IF; END LOOP; COMMIT; SELECT CONCAT('完了',cnt); CLOSE cur_tbls; END ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值