Angel Deeyaz Ответов: 1

Получить сумму требуемых значений (с фильтром) в datatable VB.NET


I have a datatable with the following fields:

Day
Date
Room Rate
No of Person
Amount
The data is as follows:

<pre>
Day Date    Room No.    Room Rate   No. of Person       Amount
1   4/9/2018    101         900.00      2           1, 800.00
2   4/10/2018   101         900.00      2           1, 800.00
3   4/10/2018   101         900.00      2           1, 800.00
1   4/9/2018    102         1000.00     3           3, 000.00
2   4/10/2018   102         1000.00     3           3, 000.00
3   4/10/2018   102         1000.00     3           3, 000.00


Я хотел бы получить общую сумму, получив сумму суммы. Но, последний день для каждого номера не должен быть включен. В приведенном выше примере общая сумма составит 9 600,00, так как номер 101 и номер 102 дня 3 не включены.

Я попытался использовать функцию datatable compute, но это не будет эффективно:

Convert.ToInt32(DataSet.Tables("dt_Lodging").Compute("SUM(Amount)", "Day = 3") 


День не будет ограничен 3-мя. Если у нас есть дни с 1 по 5, то день 5-это тот, который не будет включен в общую сумму.

Некоторые предлагали вычислить его по формуле стоимость номера * количество ночей (вместо количества дней. Но я должен показать запись для номеров с самого первого дня до последнего дня пребывания в указанном номере.

Что я уже пробовал:

Convert.ToInt32(DataSet.Tables("dt_Lodging").Compute("SUM(Amount)", "Day = 3") 

1 Ответов

Рейтинг:
5

Maciej Los

Проверить это:

Dim dt As DataTable = New DataTable()
dt.Columns.AddRange({New DataColumn("Day", GetType(Int32)), _
				New DataColumn("Date", GetType(DateTime)), _
				New DataColumn("Room No.", GetType(Int32)), _
				New DataColumn("Room Rate", GetType(Double)), _
				New DataColumn("No. of Person", GetType(Int32)), _
				New DataColumn("Amount", GetType(Double))})
dt.Rows.Add(New Object(){1, New DateTime(2018, 4, 9), 101, 900.00, 2, 1800.00})
dt.Rows.Add(New Object(){2, New DateTime(2018, 4, 10), 101, 900.00, 2, 1800.00})
dt.Rows.Add(New Object(){3, New DateTime(2018, 4, 10), 101, 900.00, 2, 1800.00})
dt.Rows.Add(New Object(){1, New DateTime(2018, 4, 9), 102, 1000.00, 3, 3000.00})
dt.Rows.Add(New Object(){2, New DateTime(2018, 4, 10), 102, 1000.00, 3, 3000.00})
dt.Rows.Add(New Object(){3, New DateTime(2018, 4, 10), 102, 1000.00, 3, 3000.00})


Dim result = dt.AsEnumerable() _
	.GroupBy(Function(x) x.Field(Of Int32)("Room No.")) _
	.Select(Function(grp) New With _
	{ _
		.RoomNo = grp.Key, _
		.TotalAmt = grp.Take(grp.Count-1).Sum(Function(x) x.Field(Of Double)("Amount")) _
	}) _
	.Sum(Function(x) x.TotalAmt) '9600 ;)


В LINQ[^] делает жизнь проще :) Видеть: Введение в LINQ в Visual Basic | Microsoft Docs[^]
DataTableExtensions.AsEnumerable Method (DataTable) (System.Data)[^]

Несколько слов объяснения:
Dim result = dt.AsEnumerable() _ 'Returns an IEnumerable<T> object, where the generic parameter T is DataRow
	.GroupBy(Function(x) x.Field(Of Int32)("Room No.")) _ 'group data by [Room No.]
	.Select(Function(grp) New With _ 'select
	{ _
		.RoomNo = grp.Key, _ '[Room No.]
		.TotalAmt = grp.Take(grp.Count-1) 'skip last row!!!
                          .Sum(Function(x) x.Field(Of Double)("Amount")) _ 'get sum of amount for each room
	}) _
	.Sum(Function(x) x.TotalAmt) 'get total amount



Перечислимый.GroupBy(TSource, TKey, TElement) Способ (Интерфейс IEnumerable(Метод), Функция(Метод TKey), Функции(Метода, TElement)) (System.Linq)[^]
Перечислимый.Граф(Способ, Метод) (Интерфейс IEnumerable(Метод), Функция(Метод Логических)) (System.Linq)[^]
Перечислимый.Take(TSource) Method (IEnumerable(TSource), Int32) (System.Linq)[^]
Перечисли.Сумма(TSource) Для (Интерфейс IEnumerable(Метод), Функция(Метод Двойной)) (System.Linq)[^]


Angel Deeyaz

Я попробовал его, и его результат равен 0.

 Dim groupedTable = From objtbl In BookingDataSet.Tables("dt_Lodging").AsEnumerable()                        Group objtbl By key = objtbl.Field(Of String)("RoomNo") Into Group                       Select RoomNo = key, _                      amount = Group.Sum(Function(objtbl) objtbl("Amount")) 


То, что я пытаюсь сделать, - это сгруппировать RoomNo и не включать последнюю запись для каждой группы. Приведенный выше код просто сгруппирован и получает сумму, включающую последнюю строку каждой группы.

Я новичок в Linq, но я пытаюсь наклониться и понять его. :)

Maciej Los

Я попробовал свое решение, и оно отлично работает.

Angel Deeyaz

Проблема в том, что

 .TotalAmt = grp.Take(grp.Count-1)  
.

Ошибка также возникает, если одна строка удаляется.

Maciej Los

Я не понимаю, что вы имеете в виду. Вы пробовали мое решение (основанное на вашем примере)?

Я создал .чистая скрипка: здесь

Angel Deeyaz

Я попробовал ваше решение, да, оно работает. Но когда он попробовал это сделать с моим собственным,
общая сумма равна нулю. Когда я удалил "-1" в
".TotalAmt = grp.Take(grp.Count-1) ", он отображает общую общую сумму (включая последнюю строку каждой группы).

Angel Deeyaz

Я попробовал также В скрипке с другим набором данных, и я думаю, что что-то не так.

Imports System
Imports System.Data
Imports System.Data.DataSetExtensions
Imports System.Linq
Imports System.Xml
				
Public Module Module1
	Public Sub Main()
		
	Dim dt As DataTable = New DataTable()
	dt.Columns.AddRange({New DataColumn("Day", GetType(Int32)), _
				New DataColumn("Date", GetType(DateTime)), _
				New DataColumn("Room No.", GetType(Int32)), _
				New DataColumn("Room Rate", GetType(Double)), _
				New DataColumn("No. of Person", GetType(Int32)), _
				New DataColumn("Amount", GetType(Double))})
dt.Rows.Add(New Object(){1, New DateTime(2018, 4, 9), 101, 900.00, 2, 1800.00})	
dt.Rows.Add(New Object(){2, New DateTime(2018, 4, 10), 101, 900.00, 2, 1800.00})	
dt.Rows.Add(New Object(){3, New DateTime(2018, 4, 10), 101, 900.00, 2, 1800.00})	
dt.Rows.Add(New Object(){1, New DateTime(2018, 4, 9), 102, 1000.00, 3, 3000.00})	


	Dim result = dt.AsEnumerable() _
		.GroupBy(Function(x) x.Field(Of Int32)("Room No.")) _
		.Select(Function(grp) New With _
		{ _
			.RoomNo = grp.Key, _
			.TotalAmt = grp.Take(grp.Count-1).Sum(Function(x) x.Field(Of Double)("Amount")) _
		}) _
		.Sum(Function(x) x.TotalAmt)
		
	Console.WriteLine("result: {0}", result)					
							
	End Sub
End Module


Результат должен быть 6, 600.00.

результат = 1800 + 1800 + 3000

Maciej Los

Почему 6600,00?
Вы хотели пропустить последнюю запись. В этом случае последний = первый для комнаты № 102.
Если вы хотите получить 6600,00, измените свой код на:

.TotalAmt = grp.Take(If(grp.Count>1,grp.Count-1, 1)).Sum(Function(x) x.Field(Of Double)("Amount")) _

Angel Deeyaz

Следует пропустить последнюю запись каждой группы.

Он работает в нашем демонстрационном образце. Однако после изменения кода в моем конце он суммирует сумму, включая последнюю запись каждой комнаты(группы).

Angel Deeyaz

Я не знаю, потому ли это, что моя таблица данных фильтруется по дням.

CPallini

5.

Maciej Los

Спасибо, Карло.

Angel Deeyaz

Я получил его несколько дней назад. Спасибо!

Maciej Los

Всегда пожалуйста. Пожалуйста, примите мой ответ как решение (зеленая кнопка), чтобы удалить ваш вопрос из списка без ответа.
Овации,
Мацей