SQL查询多次返回相同的记录

时间:2013-08-12 13:34:37

标签: c# sql sql-server database tsql

我正在为我的大学项目进行自动注册。我使用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: 再次检查表格,并留下一些虚拟条目。你仍然很棒,我在编程时仍然不好:)

3 个答案:

答案 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查询中多个记录进行故障排除的一些方法,这些记录始终可以捕获错误:

  1. 检查JOINSELECT查询中单独使用的每个表,看看是否可以在每个表中找到多个记录时应该只有一个(通常是问题 - 一个副本可以创建一个巨大的乱七八糟)。
  2. 有时当人们编码LEFT JOIN时,他们确实需要INNER JOIN(反之亦然)。在获取重复项时,JOIN混淆也可能是一个巨大的问题。
  3. 仔细检查WHERE子句或JOIN条件。有时会在一个会消除某些记录的子句中缺少过滤器。
  4. 当您获得不产生重复项的数据库查询时,使用 IF 上面的数据库结果查询结果为16条记录。
  5. <强>更新

    出色!现在,将您的联接更改为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)

  1. 确认tagid在用户表中是唯一的。

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

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

    string Plus30Min = TimePlus.ToString(“hh:mm tt”);