我正在尝试用Linq订购一个查询,该查询在SQL服务器中有几行,其中有一个查询结果,我想按客户端将其分组,从而在每年的一列中向我显示信息。
要处理的查询如下:
año mes Oficina Cliente Moneda total
--------------------------------------------
2017 3 O1 Cliente1 USD 3250
2017 5 O1 Cliente1 USD 55000
2018 3 O1 Cliente1 USD 7900
2018 4 O1 Cliente1 USD 7900
2018 7 O1 Cliente1 USD 7900
2017 3 O2 Cliente2 EUR 145,7
2017 7 O2 Cliente2 EUR 6000
2017 2 O2 Cliente3 USD 23250
2017 3 O2 Cliente3 USD 2331,64
2017 4 O2 Cliente3 USD 1504,32
2017 5 O2 Cliente3 USD 1504,32
您要显示以下内容:
oficina cliente enero febrero marzo abril .... diciembre total
======== ======== ======= ======= ======= ===== ======= ========= =====
我想知道是否有一种方法可以通过Linq获得预期的结果。
答案 0 :(得分:1)
-编辑以反映vb.net
这最好在您的表示层中完成,例如在Javascript / HTML中。无论如何,您正在做的用例都是演示性的,所以我建议您仔细研究一下。
但是,如果您确实希望在业务逻辑层完成此操作,那么您的策略取决于您要如何表示对象。但是,我假设您要处理强类型对象。如果是这样,那么有一种方法,但是您不会喜欢它。
首先,让我们创建一个类来表示样本数据的结构。当然,您可以在实现中将属性名称返回为西班牙语格式。
Class row
Public year As Integer
Public month As Integer
Public office As String
Public client As String
Public currency As String
Public total As Double
Public Sub New(ByVal y As Integer, ByVal m As Integer, ByVal o As String, ByVal cl As String, ByVal cu As String, ByVal t As Double)
year = y
month = m
office = o
client = cl
currency = cu
total = t
End Sub
End Class
然后让我们用示例数据填充一个列表:
Dim rows = New List(Of row) From {
New row(2017, 3, "O1", "Cliente1", "USD", 3250),
New row(2017, 5, "O1", "Cliente1", "USD", 55000),
New row(2018, 3, "O1", "Cliente1", "USD", 7900),
New row(2018, 4, "O1", "Cliente1", "USD", 7900),
New row(2018, 7, "O1", "Cliente1", "USD", 7900),
New row(2017, 3, "O2", "Cliente2", "EUR", 145.7),
New row(2017, 7, "O2", "Cliente2", "EUR", 6000),
New row(2017, 2, "O2", "Cliente3", "USD", 23250),
New row(2017, 3, "O2", "Cliente3", "USD", 2331.64),
New row(2017, 4, "O2", "Cliente3", "USD", 1504.32)
}
将来,像我一样显示您的示例数据,您将在帮助您的过程中更轻松。
接下来,我们要代表您的数据透视表的结构:
Class pivotedRow
Public year As Integer
Public office As String
Public client As String
Public currency As String
Public Jan As Double?
Public Feb As Double?
Public Mar As Double?
Public Apr As Double?
Public May As Double?
Public Jun As Double?
Public Jul As Double?
Public Aug As Double?
Public Sep As Double?
Public Oct As Double?
Public Nov As Double?
Public Dec As Double?
End Class
要进行透视,我首先将关键字段分组,以作为围绕其进行旋转的支点。然后,从组中选择这些键,以及每个月的计算结果,该计算将输出与该月匹配的记录的total
字段。
Dim result = rows.GroupBy(Function(r) New With {r.year, r.office, r.client, r.currency
}).[Select](Function(g) New pivotedRow With {
.office = g.Key.office,
.client = g.Key.client,
.currency = g.Key.currency,
.year = g.Key.year,
.Jan = g.SingleOrDefault(Function(r) r.month = 1)?.total,
.Feb = g.SingleOrDefault(Function(r) r.month = 2)?.total,
.Mar = g.SingleOrDefault(Function(r) r.month = 3)?.total,
.Apr = g.SingleOrDefault(Function(r) r.month = 4)?.total,
.May = g.SingleOrDefault(Function(r) r.month = 5)?.total,
.Jun = g.SingleOrDefault(Function(r) r.month = 6)?.total,
.Jul = g.SingleOrDefault(Function(r) r.month = 7)?.total,
.Aug = g.SingleOrDefault(Function(r) r.month = 8)?.total,
.Sep = g.SingleOrDefault(Function(r) r.month = 9)?.total,
.Oct = g.SingleOrDefault(Function(r) r.month = 10)?.total,
.Nov = g.SingleOrDefault(Function(r) r.month = 11)?.total,
.Dec = g.SingleOrDefault(Function(r) r.month = 12)?.total
})
您可以通过创建一个函数使此操作简单一些:
Private Function getMonthTotal(ByVal group As IEnumerable(Of row), ByVal month As Integer) As Double?
Return group.FirstOrDefault(Function(r) r.month = month)?.total
End Function
现在您可以这样做:
Dim result = rows.GroupBy(Function(r) New With {r.year, r.office, r.client, r.currency
}).[Select](Function(g) New pivotedRow With {
.office = g.Key.office,
.client = g.Key.client,
.currency = g.Key.currency,
.year = g.Key.year,
.Jan = getMonthTotal(g, 1),
.Feb = getMonthTotal(g, 2),
.Mar = getMonthTotal(g, 3),
.Apr = getMonthTotal(g, 4),
.May = getMonthTotal(g, 5),
.Jun = getMonthTotal(g, 6),
.Jul = getMonthTotal(g, 7),
.Aug = getMonthTotal(g, 8),
.Sep = getMonthTotal(g, 9),
.Oct = getMonthTotal(g, 10),
.Nov = getMonthTotal(g, 11),
.Dec = getMonthTotal(g, 12)
})
如果您不喜欢这种方式,则可以放弃静态类型并使用DataTable之类的东西。我已经使用DataTables完成了类似的数据透视。代码同样复杂,但是至少在那种情况下,它是可重用的。如果您走这条路,请认真考虑是否是最佳选择。就我而言,当我使用DataTables时,它只是供我个人使用以帮助在开发过程中查看数据,而不是供其他人使用。
答案 1 :(得分:1)
如果发表评论,这个时间太长了,但是如果此linq有任何错误或错误,我认为可以对此进行讨论,因此我将其放在此处:
Dim amountPerGroup = From row In table.AsEnumerable
Group row By myGroup = New With {
Key .ano = row.Field(Of Integer)("año"),
Key .Oficina = row.Field(Of String)("Oficina"),
Key .Cliente = row.Field(Of String)("Cliente"),
Key .Moneda = row.Field(Of String)("Moneda")
} Into Group
Select New With {
myGroup.ano, myGroup.Oficina, myGroup.Cliente, myGroup.Moneda,
.SumJan = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 1, x.Field(Of Double)("total"), 0))),
.SumFeb = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 2, x.Field(Of Double)("total"), 0))),
.SumMar = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 3, x.Field(Of Double)("total"), 0))),
.SumApr = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 4, x.Field(Of Double)("total"), 0))),
.SumMay = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 5, x.Field(Of Double)("total"), 0))),
.SumJun = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 6, x.Field(Of Double)("total"), 0))),
.SumJul = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 7, x.Field(Of Double)("total"), 0))),
.SumAug = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 8, x.Field(Of Double)("total"), 0))),
.SumSep = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 9, x.Field(Of Double)("total"), 0))),
.SumOct = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 10, x.Field(Of Double)("total"), 0))),
.SumNov = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 11, x.Field(Of Double)("total"), 0))),
.SumDec = Group.Sum(Function(x) Convert.ToDouble(IIf(x.Field(Of Integer)("mes") = 12, x.Field(Of Double)("total"), 0)))}