我正在为我的大学项目进行自动注册。我使用RFID扫描仪扫描学生的tagID,并使用它来查询我的数据库并在DataGridView中显示结果。
运行时进程是:
用户扫描标签(RFID_DataReceived处理程序触发以读取标签并执行TagExistsQuery()
以检查标签是否存在于数据库的Student
表中)
如果标签DOES存在于数据库中那么执行AttendanceQuery()
以使标签与特定讲座相匹配并在DGV中显示结果
如果标签在DB THEN中不存在,则显示错误消息
我的问题是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
编辑CD:
问题解决了。注意到其中一个表中的多个记录。我想感谢大家的帮助,指示和时间花费。像我这样的初学者很幸运有SO和喜欢自己的用户愿意提供帮助。再次感谢你!
编辑CD2:
事实证明,从CourseID-ModuleID
表中删除多个记录,仅限制了从16到4生成的记录,因此有进展,但并非完美。我尝试使用INNER而不是LEFT JOIN,但结果保持不变。
编辑CD3: 再次检查表格,并留下一些虚拟条目。你仍然很棒,我在编程时仍然不好:)
答案 0 :(得分:2)
运行此查询(替换YOURVALUE)...
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
查询中多个记录进行故障排除的一些方法,这些记录始终可以捕获错误:
JOIN
或SELECT
查询中单独使用的每个表,看看是否可以在每个表中找到多个记录时应该只有一个(通常是问题 - 一个副本可以创建一个巨大的乱七八糟)。LEFT JOIN
时,他们确实需要INNER JOIN
(反之亦然)。在获取重复项时,JOIN
混淆也可能是一个巨大的问题。WHERE
子句或JOIN
条件。有时会在一个会消除某些记录的子句中缺少过滤器。<强>更新强>
出色!现在,将您的联接更改为INNER,并查看是否获得多个记录。如果是这样,请检查每个表(Student,CourseID,ModuleID,Session),以确保只有一个表使用您在查询中看到的相同参数(在JOIN
或上面)时,没有重复项(或多个记录) WHERE
条件)。如果您有条件的多条记录,则需要在JOIN
条件(或WHERE
子句)中指定只能获得一条记录的位置。
答案 1 :(得分:0)
我猜你会得到16行而不是1行,因为每个学生可以有几门课程,每门课程有几个模块,每个模块有几个课程。如果您以相反的方式进行连接,则应获得1行(学生LEFT JOIN会话LEFT JOIN模块LEFT JOIN课程,假设课程为多个模块,而不是相反。)。 但是,如果学生没有会话,你就会得到一排。
我猜你真正想要使用的是INNER JOIN。
如果行数超过零,也可以使用SQL'EXISTS'代替选择然后计数。
答案 2 :(得分:0)
确认tagid在用户表中是唯一的。
将se.SessionTimeStart
和se.SessionTimeEnd
添加到查询结果中。我怀疑过去一些永无止境的会议开始了。
确保这是24小时制,而不是12小时制:
string Plus30Min = TimePlus.ToString(“hh:mm tt”);