2012-01-15 35 views
0

我有一个数据库,在那里我保存提供贷款的人的数据。贷款只能由一个人或一群人来完成。我向你展示了我的数据库模式的一部分。按树形格式分组

enter image description here

“Acreditados”保持'人物角色(人)和“Creditos”(贷款),这样一个人可以有多个贷款和一笔贷款可能由多人作出之间的关系。 'Agrupaciones'保留'acreditados'(一个已经有贷款的人)和'grupos'(按组的贷款都有一个组名)之间的关系。 最后'movimientos'保持每个人的收费和付款。

这里的问题是如何查询我的数据库,以贷款(creditos)对所有付款(movimientos)进行分组,以及如果它是个人的个人贷款显示名称,但是如果它是组的贷款显示名称组?

我已经有以下查询:

SELECT CR.id_credito, SUM(M.monto) AS Monto, SUM(M.interes) AS Interes, SUM(M.iva) AS IVA, SUM(M.capital) AS Capital, M.fecha_mov 
FROM movimientos AS M 
JOIN cargos AS C ON C.id_movimiento = M.id_movimiento 
JOIN acreditados AS A ON A.id_acreditado = M.id_acreditado 
JOIN creditos AS CR ON CR.id_credito = A.id_credito 
WHERE C.status = 0 
GROUP BY CR.id_credito, M.fecha_mov 
ORDER BY M.fecha_mov 

与此查询我组付款的“creditos”(贷款)和日期,因为每次支付都有不同的日期。但我该如何与'personas'(person)表一起加入以获得贷款人的姓名,并且如果它是按组的小组名称显示的贷款?实际上,如果传统查询可能会发生这种情况,并且这种做法是在c#中创建一个三维视图,其中组的名称将是父项,每个人都是子节点,那么实际上我不这么做。个人贷款将是没有孩子的父母节点。 任何帮助,将不胜感激,谢谢

+0

做一个“个人”贷款一组只有一个成员(默认为成员的名字吗?),节省了群众的问题,并为您提供设施,以债权人的其他添加和删除到“组”。相信我你不想要这个群体/单独的分裂,它会比这个更多的时间在你的脸上。 – 2012-01-15 18:55:35

+0

因此,您认为在'agrupaciones'中插入个人贷款时,将组名设置为默认成员的名称可以解决这个问题?但是三看门人呢?如果我这样做,我怎样才能在三维视图中显示子节点中的人员信息? – 2012-01-15 19:18:48

+0

你的问题来自处理贷款的一个或多个作为两个不同的事情。贷款 - >小组 - >借款人。如果组中只有一个借用者,那么您可以跳过中间节点,但这是构建树时的子数,您的查询将是相同的,并且与演示不可知。 – 2012-01-16 00:37:12

回答

0

我会很关心加入额外的表,可能会重复行,从而抛出所有的聚合函数。我的意思是这样的:

假设你有两个人附加贷款,所以你从贷款支付开始,加入贷款,然后加入属于该贷款的人。您现在必须为每笔贷款付款(每个人一份)记录2条记录,您现在必须处理这些记录。

我会建议做的是使用外部应用程序将字段加入到您所需的内容中。如果您从未使用过外/交叉应用,只是把它作为一个select语句的子查询:

SELECT (SELECT TOP 1 i.someColumn FROM innerTable i WHERE i.ID = t.ID) FROM someTable AS t 

除了它的内加入本身。这意味着您可以在FROM子句中使用IN SCOPE子查询来重新加入。事实上,这可能是你最好的选择,为了保持所有支付本地化为贷款,并保留所有人/组在这个其他查询。所以,你的查询会是这个样子:

SELECT CR.id_credito, SUM(M.monto) AS Monto, SUM(M.interes) AS Interes, SUM(M.iva) AS IVA, SUM(M.capital) AS Capital, M.fecha_mov, ISNULL(tg.nombre, tp.nombre) Nombre 
FROM movimientos AS M 
JOIN cargos AS C ON C.id_movimiento = M.id_movimiento 
JOIN acreditados AS A ON A.id_acreditado = M.id_acreditado 
JOIN creditos AS CR ON CR.id_credito = A.id_credito 
OUTER APPLY (SELECT TOP 1 G.nombre FROM grupos G JOIN agrupaciones AG on AG.id_grupo = G.id_grupo WHERE AG.id_acreditado = A.id_acreditado) tg 
OUTER APPLY (SELECT TOP 1 P.nombre FROM personas P WHERE P.id_persona = A.id_persona) tp 
WHERE C.status = 0 
GROUP BY CR.id_credito, M.fecha_mov, ISNULL(tg.nombre, tp.nombre) 
ORDER BY M.fecha_mov 

一件事夺去这是外适用不需要连接回表中的其余FROM子句,因为它已经假设您基于来自FROM子句源(表)的其余部分的值进行查询。此外,不要忘记别名您的APPLY查询(在这种情况下,它是tgtp)。

编辑:刚才注意到需要树视图格式。我现在就解决这个问题。

看来,无论如何,你希望每个人的所有记录也能被返回。在这种情况下,您希望为组内的所有人返回相同的记录。我认为最好的办法是以普通加入的方式回到人员表格(而不是应用),然后按tg.nombrepersonas.nombre字段进行分组。这样,您仍然可以获得每个附加到贷款的人,但您也可以返回组名,以便如果有组,则可以将其用作树中的根节点。

至于实际创建这个树视图,你将不得不做一些额外的工作,以实际上得到它的设置。我建议的是以可用格式获取查询,并使用LINQ分组将它们一起编译。

查询,然后将需要改变这样: 在上面的变化而变化的线OUTER APPLY (SELECT TOP 1 P.nombre FROM personas P WHERE P.id_persona = A.id_persona) tpINNER JOIN personas P on P.id_persona = A.id_persona,改变选择/分组从ISNULL(tg.nombre, tp.nombre) Nombretg.nombre Grupo, P.nombre Nombre。在代码中,取回您的查询结果后,请使用以下LINQ语句获取查询(假设它至少.NET 3.5):

// Assume the query results are in dtLoanPayments strongly typed datatable. 
// Also assume we have a TreeView called tvLoans 
dtLoanPayments.AsEnumerable().GroupBy(tr => tr.Grupo).ToList().ForEach(tr => 
{ 
    (tr.Key == null ? tvLoans.Nodes : tvLoans.Nodes.Add(tr.Key)).AddRange 
     (tr.Select(ti => { TreeNode tempNode = new TreeNode(ti.Nombre); tempNode.Tag = ti; return tempNode; }).ToArray()); 
}); 

再次,它真的只是取决于你如何希望他们显示。如果你想进一步分组,那么你需要在内部tr.Select前做另一个GroupBy,因此它会是tr.GroupBy(ti => ti.Personas).Select,你必须为每个贷款支付记录创建另一个TreeNode。在这些类型的情况下,请记住保持显示和数据逻辑分离通常要容易得多。在查询方面,只要确保你找回的数据是正确的,然后在应用程序代码中处理格式。

编辑:要回答你的评论问题,添加一些更多的代码。 这只是将您的项目列表转换为正确嵌套的TreeNode对象的问题。我想我上面的解释可以回答这个问题,但我可以给你解释代码的解释。假设你的列表被称为amortList和您的TreeView被称为tvLoans,那就试试这个:

// First, group by group name. If it's null (meaning no group), then it will just be 
// the person's name. Doing ToList() after grouping so we can do a ForEach. 
amortList.GroupBy(tr => string.IsNullOrEmpty(tr.Grupo) ? tvLoans : tvLoans.Add(tr.Grupo)).ToList() 
    .ForEach(tr => 
    // This gives us the node we'll be adding each record to as the key. Now all 
    // we need to do is add all loan records to the node, grouping by person 
    { 
     tr.Key.Nodes.AddRange(
      // Group by person's name first 
      tr.GroupBy(ti => new TreeNode(ti.Nombre)) 
       // Then transform into each node (loan payment, etc) and add to the person node. 
       .Select(ti => 
       { 
        ti.Key.Nodes.AddRange(
         ti.Select(tn => new TreeNode(/*Use whatever field here to display.*/).ToArray()); 
        return ti.Key; // Return TreeNode. 
       }).ToArray()); 
    } 

如果这仍然是混乱的,你可以做,完成同样的事情(和更容易理解)一个foreach。

foreach(_Amortizacion amNode in amortList) 
{ 
    // Using Null Coalescing to create the node if it doesn't exist. 
    // First check if group is null. If it isn't, try to pull the node and create it if it doesn't exist. 
    TreeNodeCollection workingNode = !string.IsNullOrEmpty(amNode.Grupo) ? 
     (tvLoans.Nodes[amNode.Grupo] ?? tvLoans.Nodes.Add(amNode.Grupo)).Nodes : 
     tvLoans.Nodes; 
    // At this point, workingNode is the NodeCollection we'll be adding the person to. Creating if doesn't exist. 
    workingNode = (workingNode[amNode.Personas] ?? workingNode.Add(amNode.Personas)).Nodes; 
    // Now we're adding the actual loan record to the person Node. 
    workingNode.Add(new TreeNode(/* This is what will show up in TreeView. */) { Tag = amNode, Name = /* Specify a key here, in case you want to search. */ }); 
} 
+0

首先感谢您的帮助。我已经使用LINQ进行了查询,并按照您的建议获得了结果。我的结果存储在List <_Amortizacion>中,其中_Amortizacion具有所需的字段。我如何使用LINQ来使用该列表制作树视图部分? – 2012-01-18 18:40:44

+0

再次加入到我的答案中,为您提供更多选项。这一切都是在这个窗口中完成的,所以可能会出现一些语法错误(没有你不应该分辨的东西)。 – SPFiredrake 2012-01-19 15:59:14

+0

完美的,很好的解释。感谢您在此上花费一些时间。 – 2012-01-19 17:08:13

0

要回答你的问题,因为它涉及到当前的模式,你可以使用:

  • LEFT JOIN acreditados到人物角色和agrupaciones
  • JOIN agrupaciones到grupos
  • 使用CASE语句确定nombre是否从角色或grupos拉取

至于在树视图中构建这个,你会想要cre吃一个递归查询来提取数据。

希望这会有所帮助。

+0

但在CASE语句中计算的布尔表达式是什么?我想是这样选择 '农布雷'= \t CASE \t \t \t WHEN P.id_persona THEN P.nombres \t \t WHEN G.id_grupo THEN G.nombre \t END ,CR.id_credito ......但没有工作 – 2012-01-17 19:38:16

+0

你会检查NULL。 '当P.id_persona不是NULL,那么P.nombres ........' – user1135379 2012-01-18 00:47:58