最近在做一个选课系统来练手,遇到一个问题,困扰了好几天:用Query语句来实现数据添加时,老是重复添加相同的数据,除非重新运行程序,判断语句'是否重复语句'才会执行判断功能
界面中有两个DBGrid(DBGrid1和DBGrid2),两个按钮('添加课程'和'删除课程');DBGrid1和'课程表'(对应TBClass)连接,DBGrid2用来显示'学生已选的课程'(对应TBSelClass表),通过QSelClass这个Query来实现,
QSelClass的SQL语句是:Select Class.ID,Class.Name,Class.ClassType,Class.Mark,
       Class.WeekPeriod    //分别表示课程ID,课程名,课程类型(选修、必修),课程的学分,课程的周学时
From Class,SelClass    //Class表示课程,SelClass表示已选的课程
Where (Class.Name=SelClass.Class_Name)and(SelClass.SNo=:StuNo)    //StuNo是自己定义的一个字符型参数,表示学号{其中表Class用来存储课程信息,表SelClass用来存储学生选中的课程信息,学生自己信息的话存储在表Student中,这三个表对应的DBTables分别为
TBClass,TBSelClass和TBStudent}
'添加课程'按钮对应的语句如下:
procedure TStudent.Button1Click(Sender: TObject);
begin
  if DataModule2.TBClass.FieldByName('SelectedNum').AsInteger
     >=DataModule2.TBClass.FieldByName('Capacity').AsInteger then    {字段名SelectedNum表示'这门课程已选的人数',
 
                                                                      字段名Capacity表示'这门课程总共可容纳的学生数'}
     begin
       ShowMessage('人数已满!');
     end
  else
    begin   
     {QuerySelected是另外一个Query,在别的程序中定义过,用来判断'课程是否重复添加':  
                           var
                           QuerySelected:TQuery;    //声明QuerySelected为Query                         procedure TStudent.FormCreate(Sender: TObject);
                         begin
                           QuerySelected:=TQuery.Create(self);    //创建QuerySelected
                           QuerySelected.DataBaseName:='.\db';    //定义其位置
  
                           end;}      QuerySelected.Close; 
      QuerySelected.SQL.Clear;
      QuerySelected.SQL.Add('Select *  from SelClass');    //表SelClass里为学生已选的课程
      QuerySelected.SQL.Add('where (SNo='''+UserName+''') and (Class_Name='''+DataModule2.TBClass.FieldByName('Name').AsString+''')');    //字段SNo表示学生的学号,字段Class_Name表示对应的课程名字
                                 //UserName是别的地方定义的一个字符串,表示Trim(Edit1.Text) 
      QuerySelected.Open;
         
    if not QuerySelected.IsEmpty then    //用QuerySelected.IsEmpty来判定这课程是否已选      begin
        ShowMessage('此课程已选!');
        DataModule2.TBClass.Next;
      end
    else      {如果这门课没选过,就将Class(课程)的部分信息和Student(学生)的学号添加到表SelClass(已选课程)中}
      begin
        DataModule2.TBSelClass.Append;
        DataModule2.TBSelClass.FieldByName('SNo').AsString:=UserName;    //UserName是别的地方定义的一个字符串,表示Trim(Edit1.Text)
        DataModule2.TBSelClass.FieldByName('Student_ID').AsInteger:=DataModule2.TBStudent.FieldByName('ID').AsInteger;
        DataModule2.TBSelClass.FieldByName('Class_ID').AsInteger:=DataModule2.TBClass.FieldByName('ID').AsInteger;
        DataModule2.TBSelClass.FieldByName('Class_Name').AsString:=DataModule2.TBClass.FieldByName('Name').AsString;
        DataModule2.TBSelClass.Post;        
        {将Class中的SelectedNum加1}      
        DataModule2.TBClass.Edit;
        DataModule2.TBClass.FieldByName('SelectedNum').AsInteger:=DataModule2.TBClass.FieldByName('SelectedNum').AsInteger+1;
        DataModule2.TBClass.Post;        ShowMessage('选课成功');
          
        QuerySelected.Close;
        QuerySelected.Open;    //实现QuerySelected的刷新
      
        DataModule2.QSelClass.Open;
        DataModule2.QSelClass.Close;    //实现QSelClass的刷新,使DBGrid2中的已选课程能及时刷新
        end;
    end;end;上面这语句的流程是:学生登陆后,进去选课界面,选中了'英语'这门课程,按下'添加课程'按钮,那么语句会先判断'这门课可以容纳的人数是否已满',
如果没满则判断'这门课程该学生是否已选'(通过刚定义的QuerySelected来判断),如果没选则将这门课程的信息和学生的学号添加到
表SelClass(表示已选课程)中,然后给表Class的字段名SelectedNum加1(表示这门课的已选人数),然后对两个Query语句:QuerySelected和QSelClass
分别刷新,对QSelClass刷新的目的是为了其对应的DBGrid2能显示出最新的已选课程信息,对QuerySelected刷新本来的目的是为了让其知道刚刚添加过了
'英语',所以QuerySelected.IsEmpty 应该要变成False了,免得'英语'被重复添加
现在的问题是:我添加了'英语'这门课程后,如果马上第二次添加,'英语'会被再次添加进来,除非我第一次添加'英语'后马上关闭界面重新登陆,
              那么第二次添加'英语'的时候才会提示'此课程已选!'
            (明明已经刷新了QuerySelected怎么还是会出现重复选课的问题,已经困扰了数天,希望大家能帮忙找找原因,感激不尽!)

解决方案 »

  1.   

    上面的:
    DataModule2.QSelClass.Open; 
    DataModule2.QSelClass.Close;    //实现QSelClass的刷新,使DBGrid2中的已选课程能及时刷新 
    应该是:
    DataModule2.QSelClass.Close; 
    DataModule2.QSelClass.Open;    //实现QSelClass的刷新,使DBGrid2中的已选课程能及时刷新 //语句太多,在论坛不小心敲错了,在delphi中是正确的
    //希望大家能帮帮忙~
      

  2.   

    1.执行ShowMessage('人数已满!');怎么没有Exit及时退出,代码还在执行下去
    2.ShowMessage('此课程已选!'); 也应该Exit退出;
    3.DataModule2.TBClass.Next; 这句有什么作用,看不明白;
      

  3.   

    代码太乱
    你要是添加的时候提示是否存在可以用locate
      

  4.   

    1、2:执行了ShowMessage还要Exit退出的吗?(刚接触Delphi一个月,还不是很懂)
    3、DataModule2.TBClass.Next; 作用是:如果我添加了英语,那么添加完以后鼠标会自动移到下一门课程上,比如语文
      

  5.   

    locate应该可以用的,但我觉得locate应该是用在一一对应的比较多吧,
    比如登陆窗口的时候,用户名和密码一一对应,那时候用locate比较方便;
    现在这里的'学号'和'课程名'可以一对多,用locate不好实现吧
      

  6.   

    你到底用了几个Query??
    TBClass,TBSelClass,TBStudent,QSelClass还有一个动态的QuerySelected共5个??
      

  7.   


    你的DBGrid1和DBGrid2又是连接的那个数据集???
      

  8.   

    Query就两个啊:QSelClass和动态的QuerySelected
    TBClass,TBSelClass,TBStudent之类的只是Table了
      

  9.   

    程序最后的时候不是刷新了一次吗?QuerySelected.Close; 
    QuerySelected.Open;    //实现QuerySelected的刷新 
           
    DataModule2.QSelClass.Close; 
    DataModule2.QSelClass.Open;    //实现QSelClass的刷新,使DBGrid2中的已选课程能及时刷新 
      

  10.   

    DBGrid1连接的是TBClass,显示的所有待选的课程
    DBGrid2连接的QSelClass,显示的是该学生所有已选的课程
    当然,DBGrid和Table和Query之间还有Datasource连接
      

  11.   

    一楼的时候说错了,DBGrid2用来显示'学生已选的课程'
    '(对应TBSelClass表)'应该改成'(对应QSelClass)',忙中出错,不好意思~
      

  12.   


    添加第一次成功后,应该能弹出ShowMessage('此课程已选'); 
    不过没有退出语句,所以还会继续执行添加相同的记录一个字,"代码很乱很乱,很难看"
      

  13.   

    procedure TStudent.Button1Click(Sender: TObject); 
    begin 
      if DataModule2.TBClass.FieldByName('SelectedNum').AsInteger 
         >=DataModule2.TBClass.FieldByName('Capacity').AsInteger then    {字段名SelectedNum表示'这门课程已选的人数', 
      
                                                                          字段名Capacity表示'这门课程总共可容纳的学生数'} 
         begin 
           ShowMessage('人数已满!'); 
         end 
      else 
      /*
        begin 
        
         {QuerySelected是另外一个Query,在别的程序中定义过,用来判断'课程是否重复添加':   
                               var 
                               QuerySelected:TQuery;    //声明QuerySelected为Query                          procedure TStudent.FormCreate(Sender: TObject); 
                             begin 
                               QuerySelected:=TQuery.Create(self);    //创建QuerySelected 
                               QuerySelected.DataBaseName:='.\db';    //定义其位置 
       
                               end;}       QuerySelected.Close;  
          QuerySelected.SQL.Clear; 
          QuerySelected.SQL.Add('Select *  from SelClass');    //表SelClass里为学生已选的课程 
          QuerySelected.SQL.Add('where (SNo='''+UserName+''') and (Class_Name='''+DataModule2.TBClass.FieldByName('Name').AsString+''')');    //字段SNo表示学生的学号,字段Class_Name表示对应的课程名字 
                                     //UserName是别的地方定义的一个字符串,表示Trim(Edit1.Text)  
          QuerySelected.Open; 
              
        if not QuerySelected.IsEmpty then    //用QuerySelected.IsEmpty来判定这课程是否已选      begin 
            ShowMessage('此课程已选!'); 
            DataModule2.TBClass.Next; 
          end 
        else       {如果这门课没选过,就将Class(课程)的部分信息和Student(学生)的学号添加到表SelClass(已选课程)中} 
          begin 
            DataModule2.TBSelClass.Append; 
            DataModule2.TBSelClass.FieldByName('SNo').AsString:=UserName;    //UserName是别的地方定义的一个字符串,表示Trim(Edit1.Text) 
            DataModule2.TBSelClass.FieldByName('Student_ID').AsInteger:=DataModule2.TBStudent.FieldByName('ID').AsInteger; 
            DataModule2.TBSelClass.FieldByName('Class_ID').AsInteger:=DataModule2.TBClass.FieldByName('ID').AsInteger; 
            DataModule2.TBSelClass.FieldByName('Class_Name').AsString:=DataModule2.TBClass.FieldByName('Name').AsString; 
            DataModule2.TBSelClass.Post;          
            {将Class中的SelectedNum加1}       
            DataModule2.TBClass.Edit; 
            DataModule2.TBClass.FieldByName('SelectedNum').AsInteger:=DataModule2.TBClass.FieldByName('SelectedNum').AsInteger+1; 
            DataModule2.TBClass.Post;         ShowMessage('选课成功'); 
               
            QuerySelected.Close; 
            QuerySelected.Open;    //实现QuerySelected的刷新 
           
            DataModule2.QSelClass.Open; 
            DataModule2.QSelClass.Close;    //实现QSelClass的刷新,使DBGrid2中的已选课程能及时刷新 
            end; 
        end; 
        */end; 你看一下执行了没有
      

  14.   

    对了,QSelClass的SQL里面的参数StuNo别的地方已经赋值了,语句如下:DataModule2.QSelClass.Close;
    DataModule2.QSelClass.Params[0].AsString:=UserName;    //UserName是一个字符串变量,表示Trim(Edit.Text)
    DataModule2.QSelClass.Open;
      

  15.   

    添加第一次成功后,确实能弹出'此课程已选';'退出语句'?最后添加'Exit'吗?刚接触Delphi不久,多多包涵:)
    觉得如果多用with do语句的话应该能简练好多,不过这样的话自己看的时候明白点,毕竟刚学怕搞错:(
      

  16.   

    第一次添加成功后,再按Button1添加时,应该会执行ShowMessage('此课程已选')
    此时,要停止执行下面的代码才是,不然会再添加一次数据.
    上面的ShowMessage('人数已满!')也应该一样改两处:
    1.     begin 
           ShowMessage('人数已满!'); 
           exit; 
         end 
      else ..
    2.    if not QuerySelected.IsEmpty then    //用QuerySelected.IsEmpty来判定这课程是否已选      
          begin 
            ShowMessage('此课程已选!'); 
            exit;  
          //  DataModule2.TBClass.Next; 这句在这里做什么用,还是不明白
          end 
        else
      

  17.   

    非常感谢,我先试试,看行不:)
    //DataModule2.TBClass.Next; 作用是:如果我添加了英语,那么添加完以后鼠标会自动移到下一门课程上,比如语文
      

  18.   

    1.你程序中用了5个query或table:QuerySelected,TBClass,TBSelClass,TBStudent,QSelClass
    你看能不能把引用的数据集控件简化一下,这样代码读起来也能简单些。
    2.你的问题是因为数据没有提交到数据库,虽然,当你关闭界面后才真正提交了。
     建议你用事务控制,从数据完整性
     在最外层包:
      DataModule2.ADOConnection1.BeginTrans; //你的程序中可能用别的名字 
      try
      {在这之间加入你的代码}     {代码结整束}
        DataModule2.ADOConnection1.CommitTrans;
      except
        DataModule2.ADOConnection1.RollbackTrans;
      end;试一下吧。
      

  19.   

    确实如你所说,关闭界面后才是真正提交了,接触delphi没多久,ADOConnection还没用过,
    不过尝试着用用,非常感谢:)
      

  20.   

    1.你程序中用了5个query或table:QuerySelected,TBClass,TBSelClass,TBStudent,QSelClass 
    你看能不能把引用的数据集控件简化一下,这样代码读起来也能简单些。 
    2.你的问题是因为数据没有提交到数据库,虽然,当你关闭界面后才真正提交了。 
     建议你用事务控制,从数据完整性 
     在最外层包: 
      DataModule2.ADOConnection1.BeginTrans; //你的程序中可能用别的名字  
      try 
      {在这之间加入你的代码} 
         {代码结整束} 
        DataModule2.ADOConnection1.CommitTrans; 
      except 
        DataModule2.ADOConnection1.RollbackTrans; 
      end; 试一下吧。
      

  21.   

    ***************************************************************************思想决定行动,加入程序员在深圳QQ群,参加技术思想碰撞专业分类:
    程序员在深圳JAVA群4247660
    程序员在深圳c++群15195967
    程序员在深圳.NET群Ⅱ:12203296
    程序员在深圳TCP/IP协议栈开发:16956462
    程序员在深圳JS & AJAX群:12578377
    程序员在深圳英语学习群:23864353
    深序员在深圳VB:11055959
    程序员在深圳c++Ⅱ17409451
    程序员在深圳c++群15195967
    程序员在深圳嵌入式开发群37489763
    程序员在深圳移动开发群31501597
    程序员在深圳创业群33653422不限专业分类:
    高级群:17538442
    第三群:2650485
    第五群:29537639
    第四群:28702746
    第六群:10590618
    第七群:10543585
    第八群:12006492
    第九群:19063074
    第十群:2883885
    第十一群:25460595
    第十二群:9663807深圳程序员QQ群联盟成立两年多,拥有三十个以上的QQ群,人数达二千多人,有30%以上的成员的经验丰富的老手,包括国内外顶级大公司的成员(如微软、IBM,SUN,华为)、国内著名高校和研究院成员,和有丰富实践经验的高级程序(包括参加过上亿元的项目的架构师),有很热爱技术的成员(包括自己写过嵌入式操作系统),还有少数女程序员。现推介如下QQ群,如有兴趣速速加入:深程高级群I:17538442 深程高级群II:7120862 (深程高级群不欢迎新手,如果在深圳,月薪6K以下的别加入) c++:15195967 .NET:12203296 mobile:31501597嵌入式:37489763 JAVA:4247660  
    —————————————————————————————————————————— 
    希望大家不要认为群能给你带来什么,这只是一个平台,让同等水平的程序员有个交流的机会或许能得到一点信息或许能带来一点启发。*****************************************************************************
      

  22.   

    还有没别的见解,大家?改用Table的话倒是一切都很顺利,都能实现,就Query怎么这么麻烦
      

  23.   

    虽然还没解决,不过还是先结了,到时候Query的资料再找找