【问题标题】:How to fill a datatable from another datatable depending on field values如何根据字段值从另一个数据表中填充数据表
【发布时间】:2013-01-06 13:24:10
【问题描述】:

我教一门 9 个单元的课程,学生可以通过每个单元以“及格”、“优异”或“优异”的成绩通过。 A P 得 70 分,M 得 80 分,D 得 90 分。今年的总成绩是所有单元的总分。

他们需要在允许“M”标准之前通过所有“P”标准,并且在允许“D”标准之前他们需要所有“M”标准。 P/M/D 标准的数量因单位而异。以下学生在本单元中取得了“及格”(70 分),因为即使他获得了所有 D 标准,但他没有获得 M:

单元 1 - 脑外科

P1 - 知道大脑在哪里 - 通过
P2 - 知道哪条路向上 - 通过
M1 - 解释大脑的作用 - 通过
M2 - 男性和女性大脑之间是否存在差异 - 失败
D1 - 弄清楚为什么我的大脑无法解决这个问题 - 通过
D2 - 发明一种可以让大脑立即找出逻辑的药物 - 通过
D3——想办法靠脑力赚大钱——通过

我有一个 SqlDataReader,它用以下列填充 DataTable:unitNo、criteriaName、criteriatype(即 P/M/D)、passedOrFailed。该查询已按个别学生进行选择,因此 DataTable 仅包含一名学生的记录。它看起来像这样:

UnitNo   Citerion   Type   passed?  
1        know etc     P       Yes  
1        know etc     P       Yes  
1        explain etc  M       Yes  
1        is there etc M       No  
1        Figure etc   D       Yes  
1        invent etc   D       Yes  
1        find etc     D       Yes  
2        blah etc     P       Yes  
2        wot etc      P       Yes  
2        so etc       M       No 

我正在寻找一个看起来像这样的数据表:

UnitNo  P    M   D   Points  
1       Y    N   Y     70  
2       Y    Y   N     80  
3       N    N   N      0  
4       N    Y   Y      0  
5       Y    Y   Y     90  

...
...
…………

最后总分 - 学生有 240 分。

我对 DataTables、c# 等非常满意

有没有人有一些关于整理这个逻辑的指针?就像古尔蒙哈斯特学校里的场景……如果你能解决的话,我会亲自派老婆去给你做周日烤肉。

电脑


好的,这是包含 CSharper 答案的实际代码(也进行了编辑以添加他的额外列名的解决方案)。这显然是正确的解决方案,我只是没有完全让数字出现(我发现他在 DataRow 演员表后遗漏了括号,但这不是问题)。我在最后连接了几个测试网格以显示结果。另外我不是 linq 人,所以我不知道如何将第一个表中的单位名称添加到第二个表中,或者总分:

(注意,我使用的是 1= 未标记,2 = 失败,3 = 通过 passFail 字段)

//create the sql to extract the data
        String sqlString = "SELECT unitNo, unitName, criterionPMD, passFail FROM unitDetails INNER JOIN unitStudentRecord ON unitDetails.id = unitStudentRecord.unitDetailsId INNER JOIN unitSummary ON unitDetails.unitSummaryId = unitSummary.id WHERE studentID = '" + ((String)Session["studentID"]).Trim() + "'";
        SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["studentTutorialsConnectionString"].ConnectionString);
        SqlCommand sqlComm = new SqlCommand(sqlString, conn);
        conn.Open();
        SqlDataReader sqlTotalMarks = sqlComm.ExecuteReader();

        //create the workings out datatable and fill it
        DataTable dtWorkings = new DataTable();
        dtWorkings.Load(sqlTotalMarks);
        conn.Close();

        // create the results datatable
        DataTable dtResults = new DataTable();
        dtResults.Columns.Add("units", typeof(int));
        dtResults.Columns.Add("name", typeof(string));
        dtResults.Columns.Add("P", typeof(bool));
        dtResults.Columns.Add("M", typeof(bool));
        dtResults.Columns.Add("D", typeof(bool));
        dtResults.Columns.Add("points", typeof(int));

        //fill the results table
        foreach (var units in dtWorkings.Rows.Cast<DataRow>().GroupBy(r => r["unitNo"]))
        {
            var p = units.Where(r => r["criterionPMD"] == "P").All(r => r["passFail"] == "3");
            var m = units.Where(r => r["criterionPMD"] == "M").All(r => r["passFail"] == "3");
            var d = units.Where(r => r["criterionPMD"] == "D").All(r => r["passFail"] == "3");
            dtResults.Rows.Add(
                 units.Key,//UnitNo
                 units.Select(r => r["unitName"]).First(),//UnitName                    
                 p,
                 m,
                 d,
                 p ? (m ? (d ? 90 : 80) : 70) : 0);//Points
        }

        gvTemp.DataSource = dtWorkings;
        gvTemp.DataBind();
        gvSummary.DataSource = dtResults;
        gvSummary.DataBind();

这是 gvTemp 的网格:

   unitNo   unitName       criterionPMD passFail
    2     Computer systems  P     3
    2     Computer systems  P     1
    3     Web rubbish           P     3

这是 gvSummary 的网格:

units   name               P     M  D   points
2           Computer systems            90   
3           Web rubbish                             90

在 gvSummary 网格中,所有 PMD 标准都出现了勾选的复选框,但没有总计。我期待第 2 单元的分数为零,第 3 单元的分数为 70 分……

太近了……

【问题讨论】:

    标签: c# asp.net datatable


    【解决方案1】:

    使用 C# 类执行此操作可能有助于将问题分解为更小的部分并获得更好的可维护解决方案。但是,DataTable 肯定也可以做到这一点。数据表的另一个缺点是数据不容易实现类型安全。在此答案的第一个版本中,缺少 r["criterionPMD"] 到字符串的转换,因此存在参考比较而不是字符串比较。

                //create the workings out datatable and fill it
                DataTable dtWorkings = new DataTable();
                dtWorkings.Columns.Add("unitNo", typeof(int));
                dtWorkings.Columns.Add("unitName", typeof(string));
                dtWorkings.Columns.Add("criterionPMD", typeof(string));
                dtWorkings.Columns.Add("passFail", typeof(int));
    
                dtWorkings.Rows.Add(2, "Computer systems", "P", 3);
                dtWorkings.Rows.Add(2, "Computer systems", "P", 2);
                dtWorkings.Rows.Add(3, "Web rubbish", "P", 3);
    
                // create the results datatable
                DataTable dtResults = new DataTable();
                dtResults.Columns.Add("units", typeof(int));
                dtResults.Columns.Add("name", typeof(string));
                dtResults.Columns.Add("P", typeof(bool));
                dtResults.Columns.Add("M", typeof(bool));
                dtResults.Columns.Add("D", typeof(bool));
                dtResults.Columns.Add("points", typeof(int));
    
                //fill the results table
                foreach (var units in dtWorkings.Rows.Cast().GroupBy(r => r["unitNo"]))
                {
                    var p = units.Where(r => (string)r["criterionPMD"] == "P").All(r => (int)r["passFail"] == 3);
                    var m = units.Where(r => (string)r["criterionPMD"] == "M").All(r => (int)r["passFail"] == 3);
                    var d = units.Where(r => (string)r["criterionPMD"] == "D").All(r => (int)r["passFail"] == 3);
                    dtResults.Rows.Add(
                         units.Key,//UnitNo
                         units.Select(r => r["unitName"]).First(),//UnitName                    
                         p,
                         m,
                         d,
                         p ? (m ? (d ? 90 : 80) : 70) : 0);//Points
                }
    

    使用复杂的条件表达式,您可以确保仅在满足所有 p、m 和 d 条件时才给出 90 分。

    即使在只有通过和区分标准的单元中,这也会给出正确的结果,因此只有 90、70 或 0 分是可能的。不知道这对你有没有要求。

    在您的示例中,只有“P”标准,很难确定 70 分还是 90 分是正确的结果。此代码 sn-p 检查是否满足所有 P、M 和 D 标准,在这种情况下,即使没有 M 或 D 标准并且所有 P 标准都已通过,也会给出 90 分。我认为在您的所有现实世界场景中,您都不会遇到这种极端情况,但无论如何值得考虑这一点。

    【讨论】:

    • 好的,添加了你的代码——它显然在正确的轨道上,但仍然没有给我数字——我已经在上面问题的末尾粘贴了代码,我已经连接了几个测试 gridviews 以显示输出(格式不是很好)。它非常接近..
    • @workingclassmedia 您在单元之后添加了另一个列名,因此 resultTable.Rows.Add 在单元之后需要另一个参数。试试dtResults.Rows.Add( units.Key,//UnitNo units.Select(r =&gt; r["unitName"]).First(),//UnitName p, m, d, p ? (m ? (d ? 90 : 80) : 70) : 0);//Points
    • 好 - 解决了名称摘要问题!您的修复程序现在已编辑到我上面的代码中。但是,汇总行显示总数为 90,并且复选框出现在布尔值的位置(粘贴对它们不起作用)所有复选框都被勾选了吗?我已经对您的 linq 语句进行了研究,我可以理解其中的逻辑,我只是​​不够聪明,无法调试最后一步?
    • 优秀!我想投票,但我首先需要 15 个代表 :( 当我得到这个时,我会回来投票。一段破解代码......
    猜你喜欢
    • 2023-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 2012-04-30
    相关资源
    最近更新 更多