1

我正在为我的大学项目进行自动注册。我使用 RFID 扫描仪扫描学生的 tagID,并使用它来查询我的数据库并在 DataGridView 中显示结果。

运行时流程为:

  • 用户扫描标签(RFID_DataReceived 处理程序触发读取标签并执行TagExistsQuery()以检查标签是否存在于StudentDB 的表中)

  • 如果标签确实存在于数据库中,则执行AttendanceQuery()以将标签与特定讲座匹配并在 DGV 中显示结果

  • 如果标签在 DB 中不存在,则显示错误消息

我的问题是AttendanceQuery()多次产生相同的记录(准确地说是 16 次),而它应该只有一个。这让我疯了好几天了。希望您能提供帮助。

我的代码是:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;

namespace AutoReg
{
    public partial class RoomActiveSession : Form
    {
        // Create the serial port with basic settings
        public SerialPort port = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);

        public int tagNo;


        public RoomActiveSession()
        {
            InitializeComponent();

            //Attach a method to be called when there is data waiting in the port's buffer
            port.DataReceived += new SerialDataReceivedEventHandler(RFID_DataReceived);

            //Begin communications
            port.Open();
        }


        public void RFID_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while (port.ReadChar() != 2) ;

            int v = 0;
            port.ReadChar(); // drop 1st 2 bytes - we actually only read the lower 32-bits of the code
            port.ReadChar();

            for (int i = 7; i >= 0; i--)
            {
                int c = port.ReadChar(); // a ascii hex char
                int part = c - '0';

                // test if 'Alpha'

                if (part > 9) part -= 7;     // Quick & dirty !


                v |= part << (i * 4);
            }

            for (int i = 0; i < 5; i++)
            {
                port.ReadChar();
            }

            tagNo = v;


            this.Invoke(new MethodInvoker(delegate()
            {

                TagExistsQuery();
            }

            ));

        }

        //SQL query that checks if the scanned tag already exists in the "Student" table
        public void TagExistsQuery()
        {
            DataTable queryResult = new DataTable();
            string ConnStr = "Data Source=DUZY;Initial Catalog=AutoRegSQL;Integrated Security=True";

            SqlConnection MyConn = new SqlConnection(ConnStr);
            MyConn.Open();

            string query = @"SELECT TagID" +
               " FROM Student " +
               " WHERE TagID = @tagNo ";

            SqlCommand command = new SqlCommand(query, MyConn);

            command.Parameters.Add("tagNo", SqlDbType.Int).Value = tagNo;


            SqlDataAdapter adapter = new SqlDataAdapter(command);

            adapter.Fill(queryResult);

            if (queryResult.Rows.Count == 0)
            {
                MessageBox.Show("Unable to match scanned tag with the Student database. Please contact help desk for assistance");
                MyConn.Close();
            }
            else
            {
                MyConn.Close();
                AttendanceQuery();

            }

        }

        //SQL query that finds the current sessionID for the given tagID by comparing curent date/time with date/time saved in DB and display result in DGV
        public void AttendanceQuery()
        {
            DataTable queryResult = new DataTable();

            string ConnStr = "Data Source=DUZY;Initial Catalog=AutoRegSQL;Integrated Security=True";

            DateTime TimePlus = DateTime.Now.AddMinutes(30);
            string Plus30Min = TimePlus.ToString("hh:mm tt");

            SqlConnection MyConn = new SqlConnection(ConnStr);
            MyConn.Open();


            string query = @"SELECT s.TagID, se.SessionID, '" +
               DateTime.Now +
               "' AS ScanningTime " +
               " FROM (((Student s " +
               " LEFT JOIN [CourseID-ModuleID] cm ON s.CourseID = cm.CourseID) " +
               " LEFT JOIN [ModuleID-SessionID] ms ON ms.ModuleID = cm.ModuleID) " +
               " LEFT JOIN [Session] se ON ms.SessionID = se.SessionID) " +
               " WHERE s.TagID = @tagNo " +
               " AND se.SessionDate = cast(getdate() as date) " +
               " AND se.SessionTimeStart <= @Plus30Min " +
               " AND se.SessionTimeEnd >= @Plus30Min ";

            SqlCommand command = new SqlCommand(query, MyConn);

            command.Parameters.Add("tagNo", SqlDbType.Int).Value = tagNo;
            command.Parameters.Add("Plus30Min", SqlDbType.VarChar).Value = Plus30Min;

            SqlDataAdapter adapter = new SqlDataAdapter(command);

                adapter.Fill(queryResult);

                if (queryResult.Rows.Count == 0)
                {
                    MessageBox.Show("Unable to register student " + tagNo);
                    MyConn.Close();
                }
                else
                {

                    SetDataSouce(queryResult);
                    MyConn.Close();
                }
        }


        private void button1_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }


        public void SetDataSouce(object source)
        {
            dataGridView1.DataSource = source;
        }


     }
}

编辑:

感谢您迄今为止的贡献:

在您的大力帮助下(感谢@user123 和其他人),我设法确认以下代码还在 SSMS 上产生了 16 条记录:

DECLARE @Plus30Min TIME, @tagNo INT
SET @Plus30Min = DATEADD(MINUTE,30,GETDATE())
SET @tagNo = 4820427

SELECT s.TagID, se.SessionID
FROM (((Student s
LEFT JOIN [CourseID-ModuleID] cm ON s.CourseID = cm.CourseID)
LEFT JOIN [ModuleID-SessionID] ms ON ms.ModuleID = cm.ModuleID)
LEFT JOIN [Session] se ON ms.SessionID = se.SessionID)
WHERE s.TagID = @tagNo
AND se.SessionDate = cast(getdate() as date)
AND se.SessionTimeStart <= @Plus30Min
AND se.SessionTimeEnd >= @Plus30Min

使用 INNER JOIN 而不是 LEFT JOIN 仍然会产生 16 而不是 1

编辑光盘:

问题解决了。注意到其中一张表中的多条记录。我要感谢大家的帮助、指点和时间花费。像我这样的初学者很幸运有 SO 和像你这样愿意提供帮助的用户。再次感谢你!

编辑 CD2:

事实证明,从CourseID-ModuleID表中删除多条记录,只将产生的记录从 16 限制到 4,因此有进步,但并不完美。我尝试使用 INNER 而不是 LEFT JOIN 但结果保持不变。

编辑 CD3: 再次检查表格,以及一些假条目。你 R 仍然很棒,而我在编程方面仍然很糟糕 :)

4

3 回答 3

2

运行此查询(替换 YOURVALUEs)...

DECLARE @Plus30Min DATETIME, @tagNo INT
SET @Plus30Min = DATEADD(MINUTE,30,GETDATE())
SET @tagNo = YOURVALUE

SELECT s.TagID, se.SessionID,
FROM (((Student s
LEFT JOIN [CourseID-ModuleID] cm ON s.CourseID = cm.CourseID)
LEFT JOIN [ModuleID-SessionID] ms ON ms.ModuleID = cm.ModuleID)
LEFT JOIN [Session] se ON ms.SessionID = se.SessionID)
WHERE s.TagID = @tagNo
AND se.SessionDate = cast(getdate() as date)
AND se.SessionTimeStart <= @Plus30Min
AND se.SessionTimeEnd >= @Plus30Min

...在您的 SQL Server 中,看看是否有多个记录应该是一个(很可能是);如果是数据库问题(而不是C#问题),99% 的情况下,这就是JOIN原因。JOIN以下是我对始终可以捕获错误的查询中的多条记录进行故障排除的一些方法:

  1. JOIN检查在或中单独使用的每个表SELECT,看看是否可以在每个表中找到多个记录,而每个表应该只有一个(通常是问题 - 一个重复会造成巨大的混乱)。
  2. 有时当人们编码时LEFT JOIN,他们真的需要一个INNER JOIN(反之亦然)。 JOIN在获得重复时,混淆也可能是一个大问题。
  3. 仔细检查WHERE条款或JOIN条件。有时,会删除某些记录的子句中缺少过滤器。
  4. 当你得到一个不产生重复的数据库查询时,如果上面对数据库最终结果的查询是 16 条记录,请使用该查询。

更新:

出色的!现在,将您的联接更改为 INNER,看看您是否获得了多条记录。如果是这样,请检查每个表(Student、CourseID、ModuleID、Session)以确保没有重复(或多条记录),而应该只有一个使用您在查询中看到的相同参数(在JOINorWHERE条件下)。如果您应该对一个条件有多个记录,您需要在您的JOIN条件(或WHERE子句)中指定一个您只能获得一个记录的点。

于 2013-08-12T13:43:27.650 回答
0

我猜你得到 16 行而不是 1 行,因为每个学生可以有几门课程,每门课程有几个模块,每个模块有几个会话。如果你以相反的方式加入你应该得到 1 行(学生 LEFT JOIN 会话 LEFT JOIN 模块 LEFT JOIN 课程,假设一个课程是几个模块,而不是相反。)。但是你会得到一个例如没有会话的学生的行。

我猜你真正想要使用的是 INNER JOIN。

如果行数超过零,您也可以使用 SQL 'EXISTS',而不是选择然后计数。

于 2013-08-12T13:52:43.503 回答
0
  1. 确认 tagid 在用户表中是唯一的。

  2. 添加se.SessionTimeStartse.SessionTimeEnd到查询结果。我怀疑过去开始了一些永无止境的会议。

  3. 确保这是 24 小时制,而不是 12 小时制:

    字符串 Plus30Min = TimePlus.ToString("hh:mm tt");

于 2013-08-12T14:24:01.963 回答