数据库查询 returns 一个查询为负数,另一个为正数 - 不知道为什么

Database query returns minus number for one query and positive number for another - don't know why

我正在使用以下 NODE js 代码来 运行 时钟。对于一个特定的用户,似乎这是一个今天才出现的问题,这个特定的用户 (OPID 7) 被告知他已经工作 minus 时间,而其他用户显示他们的正确正时间工作时间?用户的opid是7

The tabular data is here,但我很困惑,因为我看不出 OPID 7 和 OPID 3 或 5 之间有任何区别...

firebird.attach(options, function(err, db) {
    if(err) throw err;
    
    app.get('/', (req, res) => {
        db.query('SELECT opid, name FROM TXOPS WHERE OPID NOT IN (1, -1, 2, 9, 10, 13, 14)', function(err, rows) {
          if(err) throw err;
  
          res.render('index', { operators: rows });
        });
      })
  
      app.get('/clock/:id', (req, res) => {
          if(req.params.id) {
              db.query('SELECT opid, name FROM TXOPS WHERE OPID = ' + req.params.id, function(err, operator_row = []) {
                  if(operator_row.length === 1)
                  {
                      var clockedIn = false;
                      db.query('SELECT FIRST 1 * FROM TXATTENDETXNTS WHERE OPID = ' + req.params.id + ' AND DATETIME >= \'' + moment().startOf('day').format('YYYY-MM-DD HH:mm:ss') + '\' ORDER BY DATETIME DESC', function(err, last_row) {
                          console.log(last_row);
              if(err) throw err;
                          if(last_row.length === 1 && last_row[0].ETXNTTYPE === 0) clockedIn = true;
                      
                          if(clockedIn)
                          {
                              db.query('SELECT FIRST 10 * FROM TXATTENDETXNTS WHERE OPID = ' + req.params.id + ' AND DATETIME >= \'' + moment().startOf('day').format('YYYY-MM-DD HH:mm:ss') + '\'', function(err, today_rows) {
                                  totalMinutes = 0;
                console.log(today_rows);
                                  today_rows.push({ DATETIME: moment().format('YYYY-MM-DD HH:mm:ss')});
                                  splitRows = today_rows.reduce(function(result, value, index, array) {
                                      if (index % 2 === 0)
                                        result.push(array.slice(index, index + 2));
                                      return result;
                                  }, []);
  
                                  splitRows.forEach(pair => {
                                      totalMinutes += Math.round(moment.duration(moment(pair[1].DATETIME).diff(moment(pair[0].DATETIME))).asMinutes());
                                  });
  
                                  console.log(totalMinutes);
  
                                  minuteString = null;
                                  hours = 0;
                                  remainingMinutes = 0;
                                  if(totalMinutes > 60)
                                  {
                                      hours = Math.floor(totalMinutes / 60);
                                      remainingMinutes = totalMinutes - (hours * 60);
                                  }
  
                                  if(hours > 0 && remainingMinutes > 0)
                                  {
                                      minuteString = hours + ' hours and ' + remainingMinutes + ' minutes'
                                  }
                                  else if(hours > 0 && remainingMinutes === 0)
                                  {
                                      minuteString = hours + ' hours';
                                  }
                                  else {
                                      minuteString = totalMinutes + ' minutes';
                                  }
  
                                  res.render('clock', { operator: operator_row[0], working_string: minuteString, clockedIn: clockedIn });
  
                              });
                          }
                          else
                          {
                              res.render('clock', {operator: operator_row[0], clockedIn: clockedIn})
                          }
                      });
  
                  }
              });
          }
      })
  
      app.get('/clock-in/:id', (req, res) => {
          db.query('SELECT opid, name FROM TXOPS WHERE OPID = ' + req.params.id, function(err, rows) {
  
              if(rows.length === 0) 
              {
                  res.render('error');
              }
  
              // Check if he's already clocked in
              db.query('SELECT FIRST 1 OPID FROM TXATTENDETXNTS WHERE OPID = ' + req.params.id + ' ORDER BY ATTENDETXNTID DESC', function(err, rows) {
                  if(err) throw err;
  
                  if(rows.length === 1 && rows[0].ETXNTTYPE == 0)
                  {
                      res.render('error');
                  }
                  else
                  {
                      db.query('SELECT FIRST 1 ATTENDETXNTID FROM TXATTENDETXNTS ORDER BY ATTENDETXNTID DESC', function(err, rows) {
                          lastID = 0;
                          if(rows.length === 1)
                          {
                              lastID = rows[0].ATTENDETXNTID;
                          }
  
                          db.query('INSERT INTO TXATTENDETXNTS (ATTENDETXNTID, OPID, DATETIME, ETXNTTYPE, SCANNEDSTR, BRANCHID, CHANGED_FLAG, DEPTID) VALUES (' + (lastID + 1) + ','+ req.params.id +', \'' + moment().format('YYYY-MM-DD HH:mm:ss') + '\', 0, null, 1, 1, 0)', function(err, rows) {
                              if(err) throw err;
  
                              res.render('success');
                                                            client.publish('timeclock'+ req.params.id, 'clocked in');
                                                            
                          });
                      });
                  }
              });
          });
        })
  
        app.get('/clock-out/:id', (req, res) => {
          db.query('SELECT opid, name FROM TXOPS WHERE OPID = ' + req.params.id, function(err, rows) {
  
              if(rows.length === 0) 
              {
                  res.render('error');
              }
  
              // Check if he's already clocked out
              db.query('SELECT FIRST 1 OPID FROM TXATTENDETXNTS WHERE OPID = ' + req.params.id + ' ORDER BY ATTENDETXNTID DESC', function(err, rows) {
                  if(err) throw err;
  
                  if(rows.length === 1 && rows[0].ETXNTTYPE == 1)
                  {
                      res.render('error');
                  }
                  else
                  {
                      db.query('SELECT FIRST 1 ATTENDETXNTID FROM TXATTENDETXNTS ORDER BY ATTENDETXNTID DESC', function(err, rows) {
                          lastID = 0;
                          if(rows.length === 1)
                          {
                              lastID = rows[0].ATTENDETXNTID;
                          }
  
                          db.query('INSERT INTO TXATTENDETXNTS (ATTENDETXNTID, OPID, DATETIME, ETXNTTYPE, SCANNEDSTR, BRANCHID, CHANGED_FLAG, DEPTID) VALUES (' + (lastID + 1) + ','+ req.params.id +', \''+ moment().format('YYYY-MM-DD HH:mm:ss') +'\', 1, null, 1, 1, 0)', function(err, rows) {
                              if(err) throw err;
  
                              res.render('success');
                                                            client.publish('timeclock'+ req.params.id, 'clocked out');
                          });
                      });
                  }
              });
          });
        })
        app.get('/break-out/:id', (req, res) => {
          db.query('SELECT opid, name FROM TXOPS WHERE OPID = ' + req.params.id, function(err, rows) {
  
              if(rows.length === 0) 
              {
                  res.render('error');
              }
  
              // Check if he's already clocked out
              db.query('SELECT FIRST 1 OPID FROM TXATTENDETXNTS WHERE OPID = ' + req.params.id + ' ORDER BY ATTENDETXNTID DESC', function(err, rows) {
                  if(err) throw err;
  
                  if(rows.length === 1 && rows[0].ETXNTTYPE == 1)
                  {
                      res.render('error');
                  }
                  else
                  {
                      db.query('SELECT FIRST 1 ATTENDETXNTID FROM TXATTENDETXNTS ORDER BY ATTENDETXNTID DESC', function(err, rows) {
                          lastID = 0;
                          if(rows.length === 1)
                          {
                              lastID = rows[0].ATTENDETXNTID;
                          }
  
                          db.query('INSERT INTO TXATTENDETXNTS (ATTENDETXNTID, OPID, DATETIME, ETXNTTYPE, SCANNEDSTR, BRANCHID, CHANGED_FLAG, DEPTID) VALUES (' + (lastID + 1) + ','+ req.params.id +', \''+ moment().format('YYYY-MM-DD HH:mm:ss') +'\', 1, null, 1, 1, 0)', function(err, rows) {
                              if(err) throw err;
  
                              res.render('success');
                                                            client.publish('timeclock'+ req.params.id, 'broke out');
                          });
                      });
                  }
              });
          });
        })              
})

数据库中的行 table 没有特定的顺序,它们的位置取决于插入的顺序,在数据页上可用 space 免费,插入时哪些页被锁定,和其他因素。此外,查询的结果可能会受到查询计划(包括索引使用)和 I/O 考虑因素的影响。

您的代码 - 特别是 SELECT FIRST 10 * FROM TXATTENDETXNTS ... 查询 - 假定较旧的行在较新的行之前返回。但是,这并不能保证,因此当较新的行出现在较旧的行之前时,您将得到负值。在为计算选择行时,您需要明确指定 ORDER BY(例如 ORDER BY DATETIME)。