用户对excel的操作很熟悉,提出要把数据库的内容导出到excel,修改后可以再导回数据库,我觉的这种做法不是很好,但想不出一个好的理由来说服他们。请大家说说这样做有什么不好,有没有可能实现(我用的数据库是sql 用ado连接,已经实现从数据库导出到excel),谢谢

解决方案 »

  1.   

    可以实现的(实际上你可以参考SQLServer2000的"导入与导出数据"功能)
    不过不建议你这么无条件地满足用户的要求。
    在我看来,最主要的一点是,是数据的安全性、完整性问题:
    由于数据直接从Excel->Database,所有的企业逻辑(特别是约束条件),只要不是在SQL Server中建立了约束、Trigger的,都将无法实现。这将导致数据的安全问题。
      

  2.   

    在C++Builder中用Ole控制Excel表
    黑龙江省通信公司 姜宏华利用C++Builder的快速报表做表格是比较麻烦的事儿。如果打出来的表格需要手工修改数据,或者要保存成可以编辑的文件,那怎么办?现在许多单位用的都是Excel表格,如何让程序做出来的报表和Excel兼容,也是问题。那么就可以让C++Builder直接操作Excel表,这样就方便多了。
    笔者在实际工作中经常用Excel表做数据报表,大多数表格的数据都要从数据库中读取,这样我就用C++Builder做了一个报表程序,方便了很多,现在把它共享给C++Builder爱好者们,就算为丰富C++Builder的文档资料做点事情吧。
    首先把Excel报表文件保存到一个指定目录下,最好放在可执行程序的子目录下,作为模板文件。可以把报表标题、表头等设置好。这里是保存在trpt子目录下。
    然后建一个report目录,作为报表目标文件夹,存放填好数据的报表,可以由用户直接操作。
    好,现在就来工作吧。
    首先确定在你的机器中装有Office。这里一Office2000为例。
    在C++Builder中新建一个工程,在窗体Form1上面放一个两个按钮SaveButton和ReadButton,分别用来保存数据到Excel表和显示刚刚保存的Excel表。
    在SaveButton按钮的单击事件中把从数据库中取到的数据放入到指定的Excel表中并将改文件拷贝到report目录下。在ReadButto按钮的单击事件中显示report目录下的报表文件,方便用户修改和另外保存。
    在Form1.h头文件中定义几个变量:
    private:
    Variant Ex,Wb,Sheet,ERange,EBorders;
    并在文件头中包含如下语句:
    #include "Excel_2K_SRVR.h"
    #include <OleServer.hpp>
    在Form1.cpp的文件头中加入
    #pragma link "Excel_2K_SRVR"
    主要代码如下:
    void __fastcall TForm1:: SaveButtonClick(TObject *Sender)
    {
    try
    {
    SaveButton->Enabled = false;
    ReadButton->Enabled = false;//使两个按钮无效//取报表文件CardSend.xls的完整目录名
    AnsiString ExcelFileName = GetCurrentDir()+"\\trpt\\table.xls"; if(!FileExists(ExcelFileName))
    {
    Application->MessageBox("报表模板文件不存在,无法打开!",
    "错误",MB_ICONSTOP|MB_OK);
    return;
    }
    //建立Excel的Ole对象Ex
    try
    {
    Ex = Variant::CreateObject("Excel.Application");
    }
    catch(...)
    {
    Application->MessageBox("无法启动Excel","错误",MB_ICONSTOP|MB_OK);
    return;
    }
    //设置Excel为不可见
    Ex.OlePropertySet("Visible",false);
    //打开指定的Excel报表文件。报表文件中最好设定只有一个Sheet。
    Ex.OlePropertyGet("WorkBooks").OleProcedure("Open",ExcelFileName.c_str());
    Wb = Ex.OlePropertyGet("ActiveWorkBook");
    Sheet = Wb.OlePropertyGet("ActiveSheet");//获得当前默认的Sheet//清空Excel表,这里是用循环清空到第300行。对于一般的表格已经足够了。
    AnsiString strRowTemp; 
    AnsiString strRange;
    int iCols,iRows;//记录列数和行数/*从第三行开始,到第300行止。一般第一行是表标题,第二行是副标题或者制表日期。*/
    for(iRows=3;iRows<300;iRows++)
    { //假设只有6列。
    for (iCols = 1;iCols < 7; iCols++)
    {
    //清空行
    Sheet.OlePropertyGet("Cells",iRows,iCols).OlePropertySet("Value","");
    }
    //去掉表格边框
    strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);//获取操作范围
    ERange = Sheet.OlePropertyGet("Range",strRange.c_str());
    EBorders = ERange.OlePropertyGet("Borders");//获取边框对象
    EBorders.OlePropertySet("linestyle",xlNone);
    }AnsiString strPtrDate; //存放当前日期,作为制表日期
    DateSeparator = '-';
    ShortDateFormat = "yyyy/m/d";//设置为年/月/日格式strPtrDate = DateToStr(Date());//取当前日期AnsiString strYear = strPtrDate.SubString(1,4);
    strPtrDate = strPtrDate.SubString(6,strPtrDate.Length()-5);
    AnsiString strMonth = strPtrDate.SubString(1,strPtrDate.Pos("-")-1);
    AnsiString strDay = 
    strPtrDate.SubString(strPtrDate.Pos("-")+1,
    strPtrDate.Length()-strPtrDate.Pos("-"));
    strPtrDate = strYear+"年"+strMonth+"月"+strDay+"日";AnsiString strData = "报表标题";//报表标题
    //将报表标题置于第一行第一列。在此之前,应将报表文件的标题格式设定好。
    Sheet.OlePropertyGet("Cells",1,1).OlePropertySet("Value",
    strData.c_str());
    //将制表日期置于表格第二行的右侧。
    Sheet.OlePropertyGet("Cells",2,5).OlePropertySet("Value",
    strPtrDate.c_str());iRows = 3;//在第三行放置表格的列名
    Sheet.OlePropertyGet("Cells",iRows,1).OlePropertySet("Value","列名1");
    Sheet.OlePropertyGet("Cells",iRows,2).OlePropertySet("Value","列名2");
    Sheet.OlePropertyGet("Cells",iRows,3).OlePropertySet("Value","列名3");
    Sheet.OlePropertyGet("Cells",iRows,4).OlePropertySet("Value","列名4");
    Sheet.OlePropertyGet("Cells",iRows,5).OlePropertySet("Value","列名5");
    Sheet.OlePropertyGet("Cells",iRows,6).OlePropertySet("Value","列名6");
    //画表格边框,在A3:F3之间取范围
    strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);
    ERange = Sheet.OlePropertyGet("Range",strRange.c_str());
    EBorders = ERange.OlePropertyGet("Borders");
    EBorders.OlePropertySet("linestyle",xlContinuous);
    EBorders.OlePropertySet("weight",xlThin);
    EBorders.OlePropertySet("colorindex",xlAutomatic);
    iRows++;
    //从数据库中取数据(略),假设数据集放入Query1中。
    Query1->Open();//打开数据集
    //循环取数
    while(!Query1->Eof)

    //循环取字段的数据放到Excel表对应的行列中
    for(iCols=1;iCols<7;iCols++)

    strRowTemp = Query1->Fields->Fields[iCols-1]->AsString;
    Sheet.OlePropertyGet("Cells",iRows,iCols).OlePropertySet("Value",
    strRowTemp.c_str());
    }
    //画该行的表格边框
    strRange = "A"+IntToStr(iRows)+":F"+IntToStr(iRows);
    ERange = Sheet.OlePropertyGet("Range",strRange.c_str());
    EBorders = ERange.OlePropertyGet("Borders");
    EBorders.OlePropertySet("linestyle",xlContinuous);
    EBorders.OlePropertySet("weight",xlThin);
    EBorders.OlePropertySet("colorindex",xlAutomatic);
    iRows++;
    Query1->Next();
    }//while结束Wb.OleProcedure("Save");//保存表格
    Wb.OleProcedure("Close");关闭表格
    Ex.OleFunction("Quit");退出Excel
    //定义目标文件名
    AnsiString DestinationFile =
    GetCurrentDir()+"\\report\\table.xls";
    //将刚刚修改的Excel表格文件table.xls拷贝到report目录下
    if(!CopyFile(ExcelFileName.c_str(),DestinationFile.c_str(),false))
    {
    Application->MessageBox("复制文件操作失败,Excel文件可能正在使用中!",
    "错误",MB_ICONSTOP|MB_OK);
    return;
    }
    Application->MessageBox("成功完成报表保存!\n可以按\'打开Excel文件\'
    按钮进行报表工作","提示",MB_ICONINFORMATION|MB_OK);SaveButton ->Enabled = true;
    ReadButton ->Enabled=true;
    }//try结束
    catch(...)
    {
    Application->MessageBox("操作Excel表格失败!",
    "错误",MB_ICONSTOP|MB_OK);
    Wb.OleProcedure("Close");
    Ex.OleFunction("Quit");
    SaveButton ->Enabled = true;
    ReadButton ->Enabled=false;
    }
    }
    至此,完成报表数据的写入工作。如果要对完成的Excel表进行操作,可以点击“打开Excel表文件按钮”(ReadButton),进行修改,保存,打印等操作。ReadButton的单击事件如下实现:
    void __fastcall TForm1:: ReadButtonClick(TObject *Sender)
    {
    try
    {
    //指定report目录下的报表文件用于用户操作
    AnsiString ExcelFileName = 
    GetCurrentDir();+"\\report\\table.xls";if(!FileExists(ExcelFileName))
    {
    Application->MessageBox("Excel表文件不存在,无法打开!",
    "错误",MB_ICONSTOP|MB_OK);
    return;
    }try
    {
    Ex = Variant::CreateObject("Excel.Application");
    }
    catch(...)
    {
    Application->MessageBox("无法启动Excel","错误",MB_ICONSTOP|MB_OK);
    return;
    }
    //使Excel可见
    Ex.OlePropertySet("Visible",true);
    //打开Excel表格文件Table.xls
    Ex.OlePropertyGet("WorkBooks").OleProcedure("Open",ExcelFileName.c_str());
    }
    catch(...)
    {
    Application->MessageBox("操作Excel表格错误!","错误",MB_ICONSTOP|MB_OK);
    Ex.OleFunction("Quit");
    }
    }以上关于C++BuilderExcel表格的操作仅作为个人观点和水平呈献给关心此问题的读者,如果有更好的方式方法,敬请指教,不胜感激。
      

  3.   

    非常同意bluemeteor(挂月||╭∩╮(︶︿︶)╭∩╮) 的说法客户由于已经用惯了word excel 还有acdsee这类的软件,所以很多东西都要求做的和他们的一样交谈的时候真想说你们不如请微软给你们做这套软件算了。我个人认为把dbgrid中的内容导出到excel文件,但没有必要做从excel导回数据库的操作直接再dbgrid界面修改保存就可以了我搜索过帖子,没有这方面的资料。请大家说说数据修改后从excel再反回数据库除了完整性之外,还会出现那些问题
      

  4.   

    同意:zjhydx98(tourist)  的说法
    用户恨不得软件的界面和操作Excel一模一样,那只能尽量模仿,毕竟这样用户用起来感觉会舒服很多
      

  5.   

    数据在excel修改后返回数据库这个问题我也解决了但用起来怪怪的,老是觉得很容易出现问题而且调用excel需要一点时间,有没有更好的办法提高速度和稳定性