查询有效但无法检索数据

Query works but cant retrieve the data

我是 Node.js 的新手(3 天总经验)。我正在使用 Node.js 和繁琐的程序包来查询数据库 (azure SQL)。我使用此处解释的示例:https://docs.microsoft.com/en-us/azure/azure-sql/database/connect-query-nodejs?tabs=macos

const connection = new Connection(config);

// Attempt to connect and execute queries if connection goes through
connection.on("connect", err => {
    if (err) {
        console.error(err.message);
    } else {
        console.log("Reading rows from the Table...");

        // Read all rows from table
        const request = new Request(
            "SELECT * FROM clients",
            (err, rowCount, columns) => {
                if (err) {
                    console.error(err.message);
                } else {
                    console.log(`${rowCount} row(s) returned`);
                }
            }
        );

        request.on("row", columns => {
            columns.forEach(column => {
                console.log("%s\t%s", column.metadata.colName, column.value);
            });
        });

        connection.execSql(request);
    }
});

我有两个问题:

  1. 我不知道如何将查询到的数据放入对象中
  2. 如果我 运行 脚本,它会将项目打印到控制台,但在完成后不会关闭连接。如果我在底部添加一个 connection.close() ,它会在完成之前关闭连接。我感觉 node.js 同时执行所有操作(我习惯了 Python..)。

更新
我找到了一种关闭连接的方法,据我所知,请求对象有几个由库预定义的“事件”。看来我需要通过 request.on('done', ...) 添加事件“完成”,以确保它甚至可以完成。我更新后的代码如下所示:

var connection = new Connection(config);

connection.connect(function(err) {
        // If no error, then good to go...
        executeStatement();
    }
);

connection.on('debug', function(text) {
        //remove commenting below to get full debugging.
        //console.log(text);
    }
);

function executeStatement() {
    request = new Request("SELECT * FROM clients", function(err, rowCount) {
        if (err) {
            console.log(err);
        } else {
            console.log(rowCount + ' rows');
        }

        connection.close();
    });

    request.on('row', function(rows) {
        _.forEach(rows, function(value, collection){
            console.log(value)
            console.log(value.value);
            console.log(value.metadata.colName)
            console.log(collection)
        })
    });

    request.on('done', function(rowCount, more) {
        console.log(rowCount + ' rows returned');
    });

    // In SQL Server 2000 you may need: connection.execSqlBatch(request);
    connection.execSql(request);
}

无论如何,非常感谢您的帮助!

问候 彼得

你可以先自定义一个class然后声明一个数组来保存对象如:

let sales = new Array();

class SalesLT{
    constructor(catagryName,productName){
        this.catagryName = catagryName;
        this.productName = productName;
    }

这里我的sql声明了returns2个属性,所以每次循环从ColumnValue[].

中取出两个元素
  request.on("row", columns => {
      for(let i=0; i<columns.length; i=i+2){
        let sale = new SalesLT(columns[i].value,columns[i+1].value);
        sales.push(sale);
      }
      
    sales.forEach( item => {
        console.log("%s\t%s",item.catagryName, item.productName)
    })
  });

代码如下:

const { Connection, Request } = require("tedious");

let sales = new Array();

class SalesLT{
    constructor(catagryName,productName){
        this.catagryName = catagryName;
        this.productName = productName;
    }
    
}
// Create connection to database
const config = {
  authentication: {
    options: {
      userName: "<***>", // update me
      password: "<***>" // update me
    },
    type: "default"
  },
  server: "<****>.database.windows.net", // update me
  options: {
    database: "<***>", //update me
    encrypt: true
  }
};

const connection = new Connection(config);

// Attempt to connect and execute queries if connection goes through
connection.on   ("connect", err => {
  if (err) {
    console.error(err.message);
  } else {
    queryDatabase();
  }
});

function queryDatabase() {
  console.log("Reading rows from the Table...");

  // Read all rows from table
  const request = new Request(
    `SELECT TOP 2 pc.Name as CategoryName,
                   p.name as ProductName
     FROM [SalesLT].[ProductCategory] pc
     JOIN [SalesLT].[Product] p ON pc.productcategoryid = p.productcategoryid`,
    (err, rowCount) => {
      if (err) {
        console.error(err.message);
      } else {
        console.log(`${rowCount} row(s) returned`);
      }
     connection.close();
    }
  );

  request.on("row", columns => {
      for(let i=0; i<columns.length; i=i+2){
        let sale = new SalesLT(columns[i].value,columns[i+1].value);
        sales.push(sale);
      }


    sales.forEach( item => {
        console.log("%s\t%s",item.catagryName, item.productName)
    })
  });

  connection.execSql(request);
}

tedious是同步包,它使用return结果的回调。所以当我们调用connection.close()时,它会关闭连接并停止回调函数。如果要关闭连接,我建议你使用async包来实现它。

例如

const { Connection, Request } = require("tedious");
const async = require("async");
const config = {
  authentication: {
    options: {
      userName: "username", // update me
      password: "password", // update me
    },
    type: "default",
  },
  server: "your_server.database.windows.net", // update me
  options: {
    database: "your_database", //update me
    encrypt: true,
    validateBulkLoadParameters: true,
  },
};

const connection = new Connection(config);
let results=[]
function queryDatabase(callback) {
  console.log("Reading rows from the Table...");

  // Read all rows from table
  const request = new Request("SELECT * FROM Person", (err, rowCount) => {
    if (err) {
      callback(err);
    } else {
      console.log(`${rowCount} row(s) returned`);
      callback(null);
    }
  });
  
  request.on("row", (columns) => {
     let result={}
    columns.forEach((column) => {
     
      result[column.metadata.colName]=column.value
      console.log("%s\t%s", column.metadata.colName, column.value);
    });
    // save result into an array
     results.push(result)
  });

  connection.execSql(request);
}
function Complete(err, result) {
  if (err) {
    callback(err);
  } else {
    connection.close();
    console.log("close connection");
  }
}
connection.on("connect", function (err) {
  if (err) {
    console.log(err);
  } else {
    console.log("Connected");

    // Execute all functions in the array serially
    async.waterfall([queryDatabase], Complete);
  }
});
connection.connect();

此外,您还可以使用包mssql。它支持异步方法并依赖包tedious。我们查询后可以直接调用close

例如

const mssql = require("mssql");
const config = {
  user: "username",
  password: "password",
  server: "your_server.database.windows.net",
  database: "your_database",
  options: {
    encrypt: true,
    enableArithAbort: true,
  },
};
let pool = new mssql.ConnectionPool(config);

async function query() {
  try {
    await pool.connect();
    const request = pool.request();
    const result = await request.query("SELECT * FROM Person");
    console.dir(result.recordset);

    await pool.close();
    console.log(pool.connected);
  } catch (error) {
    throw error;
  }
}

query().catch((err) => {
  throw err;
});

这篇文章应该可以帮助您解决您面临的所有问题...这与我开始使用 Node 时遇到的问题相同:)

https://devblogs.microsoft.com/azure-sql/promises-node-tedious-azure-sql-oh-my/