issue looping through SQL table C# - c#

My application is reading off a SQL query table and matching and displaying values in certain fields in a listview. My query SQL table looks like this
+--------------+---------+-------+----------+--------+
| process name | subtask | total | employee | date |
+--------------+---------+-------+----------+--------+
| process 1 | sub1 | 1 | 1111 | 01-May |
| process 2 | | 1 | 2222 | 05-May |
| process 3 | | 1 | 3333 | 10-May |
| process 4 | | 1 | 4444 | 07-May |
+--------------+---------+-------+----------+--------+
I have run into a problem. I have noticed by stepping through my loops (using messegebox) that process 1 is displayed in my messagebox multiple times (in MessageBox.Show(dr[0].ToString());) when it should only be displayed once and when the loop gets to process 4 the messagebox displays process 4 (in (in MessageBox.Show(dr[0].ToString());)) then the loop stops and thus does not grab the total, employee and date values. How can I fix this.
DateTime now = DateTime.Now;
var startDate = new DateTime(now.Year, now.Month, 1);
var endDate = startDate.AddMonths(1).AddDays(-1);
string[,] report = new string[,] { {"process 1", "sub1", "3", "0", "", "" },
{"process 2", "", "3", "0", "", "" },
{"process 3", "", "3", "0", "", "" }
*** there are multiple entries in this array *****
}
string totalsquery = "select Process_Name, Sub_Process1_Name, count(id) as total, Completed_By_Employee_Number, max(Refresh_Date) from testDB.dbo.Quality_Data_Master where Refresh_Date between '" + startDate + "' and '" + endDate + "' group by Process_Name, Sub_Process1_Name, Completed_By_Employee_Number, Refresh_Date";
SqlConnection con = new SqlConnection();
SqlDataAdapter ada = new SqlDataAdapter(totalsquery, con);
DataTable dt = new DataTable();
ada.Fill(dt);
listView1.View = View.Details;
listView1.Columns.Add("Process Name", 250);
listView1.Columns.Add(" Sub Task", 200);
listView1.Columns.Add("Target", 45, HorizontalAlignment.Center);
listView1.Columns.Add("Total", 40, HorizontalAlignment.Center);
listView1.Columns.Add("Employee", 100, HorizontalAlignment.Center);
listView1.Columns.Add("Date", 100);
for (int i = 0; i < dt.Rows.Count; i++)
{
DataRow dr = dt.Rows[i];
//MessageBox.Show(dr.ToString());
for (int j = 0; j < report.GetLength(0); j++)
{
if (report[j, 0].Equals(dr[0].ToString()))
{
MessageBox.Show(dr[0].ToString());
if (report[j, 1].Equals(dr[1].ToString()))
{
MessageBox.Show(dr[1].ToString());
report[j, 3] = (Int32.Parse(report[j, 3]) + (int)dr[2]).ToString();
MessageBox.Show(dr[2].ToString());
report[j, 4] = report[j, 4] + dr[3].ToString();
MessageBox.Show(dr[3].ToString());
report[j, 5] = report[j, 5] + dr[4].ToString();
MessageBox.Show(dr[4].ToString());
}
}
}
}
String[] temp = new String[7];
for (int i = 0; i < report.GetLength(0); i++)
{
temp[0] = report[i, 0].ToString();
temp[1] = report[i, 1].ToString();
temp[2] = report[i, 2].ToString();
temp[3] = report[i, 3].ToString();
temp[4] = report[i, 4].ToString();
temp[5] = report[i, 5].ToString();
//temp[6] = report[i, 6].ToString();
ListViewItem listItem = new ListViewItem(temp);
listView1.Items.Add(listItem);
}
con.Close();

I recomend to refactor your code, also.
Instead of using ListView, look at DataGridView.
With DataGridView you can simple do:
// dataGridView defined at design
// more info on [msdn][1] pages
DataTable dt = GetDataTable(...);
dataGridView.DataSource = dt;

Related

Sum column where (condition) with datatable

Suppose I have the following datatable, and i want to sum all rows where column is "money" where the month is may.
+--------------------+-------+
| Date | money |
+--------------------+-------+
| 5/3/2020 8:00:00 | 20 |
+--------------------+-------+
| 5/3/2020 11:00:00 | 10 |
+--------------------+-------+
| 8/3/2020 12:00:00 | 5 |
+--------------------+-------+
| 9/7/2020 10:00:00 | 56 |
+--------------------+-------+
| 2/11/2020 13:00:00 | 45 |
+--------------------+-------+
Expected result is 30, my code gives 0 as answer
My code is:
string data= dt.AsEnumerable()
.Where(y => y.Field<DateTime>("Date").Month==m)
.Sum(x => x.Field<int>("money"))
.ToString();
Note, I don't want a sulotion with iteration, but similar to mine (Like sql style "select from where...")
My result is 30.
var dt = new DataTable();
dt.Columns.Add("Date", typeof(DateTime));
dt.Columns.Add("money", typeof(int));
var row = dt.NewRow();
row["Date"] = new DateTime(2020, 5, 3);
row["money"] = 20;
dt.Rows.Add(row);
row = dt.NewRow();
row["Date"] = new DateTime(2020, 5, 3);
row["money"] = 10;
dt.Rows.Add(row);
row = dt.NewRow();
row["Date"] = new DateTime(2020, 8, 3);
row["money"] = 5;
dt.Rows.Add(row);
row = dt.NewRow();
row["Date"] = new DateTime(2020, 9, 7);
row["money"] = 56;
dt.Rows.Add(row);
row = dt.NewRow();
row["Date"] = new DateTime(2020, 2, 11);
row["money"] = 45;
dt.Rows.Add(row);
var sumOfValuesInMarch = dt.AsEnumerable()
.Where(x => x.Field<DateTime>("Date").Month == 5)
.Sum(x => x.Field<int>("money"))
.ToString(); // 30

How to use Linq to create unique Collection which contains a collection

I am retrieving records from a db and creating the following object:
public class RemittanceBatchProcessingModel
{
public string FileId { get; set; }
public string SourceFileName { get; set; }
public string BatchCode { get; set; }
public string BatchType { get; set; }
public decimal PaymentAmount { get; set; }
public string BillingSystemCode { get; set; }
}
Example objects created after db read:
FileId | SourceFileName | BatchCode | BatchType | PaymentAmt |BillingCode
1 | test.file1.txt | 100 | S | 1000.00 | Exc
1 | test.file1.txt | 100 | S | 2000.00 | Exc
1 | test.file1.txt | 200 | N | 500.00 | Adc
2 | test.file2.txt | 300 | S | 1200.00 | Exc
2 | test.file2.txt | 300 | S | 1500.00 | Exc
I want to create an object that has a collection of the unique files which has a collection of each summarized batch within a file. For example,
Collection of Unique Files:
FileId | SourceFileName | BatchCode | BatchType | BatchTotal |RecordCount
1 | test.file1.txt | 100 | S | 3000.00 | 2
1 | test.file1.txt | 200 | N | 500.00 | 1
2 | test.file2.txt | 100 | S | 1700.00 | 2
I am able to create my collection of batches with no issue the problem I'm having is figuring out how to create the collection of unique files with the correct batches within them. I'm attempting this using the following:
private static RemittanceCenterFilesSummaryListModel SummarizeFiles(RemittanceCenterSummaryListModel remittanceCenterSummaryListModel)
{
var summarizedBatches = SummarizeBatches(remittanceCenterSummaryListModel);
var fileResult = remittanceCenterSummaryListModel.RemittanceBatchSummaryRecord.GroupBy(x => new { x.FileId, x.SourceFileName })
.Select(x => new RemitanceCenterFileSummarizedModel()
{
FileId = x.Key.FileId,
SourceFileName = x.Key.SourceFileName,
ScannedBatchCount = x.Count(y => y.BatchType == "S"),
ScannedBatchAmount = x.Where(y => y.BatchType == "S").Sum(y => y.PaymentAmount),
NonScannedBatchCount = x.Count(y => y.BatchType != "S"),
NonScannedBatchAmount = x.Where(y => y.BatchType != "S").Sum(y => y.PaymentAmount),
});
var summaryListModel = CreateSummaryFilesListModel(fileResult);
summaryListModel.Batches = summarizedBatches.RemittanceBatchSummary;
return summaryListModel;
}
private static RemittanceCenterFilesSummaryListModel CreateSummaryFilesListModel(IEnumerable<RemitanceCenterFileSummarizedModel> summaryModels)
{
var summaryModelList = new RemittanceCenterFilesSummaryListModel();
foreach (var summaryFileRec in summaryModels)
{
var summaryModel = new RemitanceCenterFileSummarizedModel
{
FileId = summaryFileRec.FileId.ToString(CultureInfo.InvariantCulture),
SourceFileName = summaryFileRec.SourceFileName.ToString(CultureInfo.InvariantCulture),
ScannedBatchCount = summaryFileRec.ScannedBatchCount,
ScannedBatchAmount = summaryFileRec.ScannedBatchAmount,
NonScannedBatchCount = summaryFileRec.NonScannedBatchCount,
NonScannedBatchAmount = summaryFileRec.NonScannedBatchAmount
};
summaryModelList.RemittanceFilesSummary.Add(summaryModel);
}
return summaryModelList;
}
You can group it on the 4 columns including BatchType and BatchCode as well and pick the Count and sum the Amount like :
var fileResult = remittanceCenterSummaryListModel.RemittanceBatchSummaryRecord
.GroupBy(x => new
{
x.FileId,
x.SourceFileName,
x.BatchType,
x.BatchCode
})
.Select(x => new
{
FileId = x.Key.FileId,
SourceFileName = x.Key.SourceFileName,
BatchType = x.Key.BatchType,
BatchCode = x.Key.BatchCode,
BatchTotal= x.Sum(y=>y.PaymentAmt),
RecordCount = x.Count()
});
I guess you need to GroupBy FileId & BatchType instead of FileName:-
var fileResult = remittanceCenterSummaryListModel.RemittanceBatchSummaryRecord
.GroupBy(x => new { x.FileId, x.BatchType })
.Select(x =>
{
var firstObj = x.FirstOrDefault();
return new RemitanceCenterFileSummarizedModel()
{
FileId = x.Key.FileId,
SourceFileName = firstObj.SourceFileName,
BatchCode = firstObj.BatchCode,
BatchType = x.Key.BatchType,
BatchTotal = x.Sum(z => z.PaymentAmt),
RecordCount = x.Count()
};
});
Considering FileId maps to SourceFileName & BatchCode maps to BatchType you can simply store the first set in a variable like I did in firstObj to get the relevant values which are not grouped. Please check for nulls before accessing relevant properties as it may cause NRE if no set is found.
For pure linq non fluent
var files = new[] {
new { FileId = 1, SourceFileName = "test.file1.txt" , BatchCode = 100 , BatchType = "S", PaymentAmt = 1000.00 , BillingCode = "Exc" },
new { FileId = 1, SourceFileName = "test.file1.txt" , BatchCode = 100 , BatchType = "S", PaymentAmt = 2000.00 , BillingCode = "Exc" },
new { FileId = 1, SourceFileName = "test.file1.txt" , BatchCode = 200 , BatchType = "N", PaymentAmt = 500.00 , BillingCode = "Adc" },
new { FileId = 1, SourceFileName = "test.file2.txt " , BatchCode = 300 , BatchType = "S", PaymentAmt = 1200.00 , BillingCode = "Exc" },
new { FileId = 1, SourceFileName = "test.file2.txt " , BatchCode = 300 , BatchType = "S", PaymentAmt = 1500.00 , BillingCode = "Exc" }
};
var result = from file in files
group file by new { file.FileId, file.BatchCode } into fileBachGroups
select new
{
FileId = 1,
SourceFileName = fileBachGroups.First().SourceFileName,
BatchCode = fileBachGroups.Key.BatchCode,
BatchType = fileBachGroups.First().BatchType,
BatchTotal = fileBachGroups.Sum(f => f.PaymentAmt),
RecordCount = fileBachGroups.Count()
};
Console.WriteLine("FileId | SourceFileName | BatchCode | BatchType | BatchTotal |RecordCount");
foreach (var item in result)
{
Console.WriteLine("{0} | {1} | {2} | {3} | {4} | {5}",item.FileId,item.SourceFileName, item.BatchCode, item.BatchType, item.BatchTotal, item.RecordCount);
}

Improve SQL query to calculate timespan between two consecutive rows

So... I have a a table like this:
RowID | DocID | Time | DepartmentID
1 | 1001 | 2015-11-20 | 1
2 | 1001 | 2015-11-21 | 2
3 | 1002 | 2015-11-20 | 1
4 | 1001 | 2015-11-25 | 1
5 | 1002 | 2015-11-22 | 3
6 | 1002 | 2015-11-30 | 1
My goal is to get the time in days a department spends with a document before sending it to another department.
I successfully achieved this by passing above table from SQL to a datatable in C#. Then get list of DocsID, and iterate throw each item in that list filtering the datatable with DocID and only then calculate the time between consecutive rows.
So the final result looks like:
DepartmentID | DocID | Time (Days)
1 | 1001 | 2
2 | 1001 | 5
1 | 1002 | 3
3 | 1002 | 9
The problem is this function in C# is taking about 30 seconds to get this results, so I'm looking for ways to improve it.
Is it possible to get this throw SQL only without making anything in C#?
My C# function (dt is a datatable with first table):
List<Int32> listDocIDs = new List<Int32>();
foreach (DataRow dr in dt.Rows)
{
int str = Convert.ToInt32(dr["DocID"].ToString());
if (!listDocIDs.Contains(str))
listDocIDs.Add(str);
}
DataTable times = new DataTable();
times.Columns.AddRange(new DataColumn[3] { new DataColumn("DepartmentID", typeof(Int32)),
new DataColumn("DocID",typeof(Int32)),
new DataColumn("Days",typeof(Int32)) });
foreach (int DocID in listDocIDs)
{
DataTable DocID_times = new DataTable();
using (SqlConnection conn = new SqlConnection(strCon))
{
conn.Open();
SqlDataAdapter adapter = new SqlDataAdapter("getRecordsByDocID", conn);
adapter.SelectCommand.Parameters.Add("#DocID", SqlDbType.Int).Value = DocID;
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.Fill(DocID_times);
conn.Close();
}
int j = 0;
for (int i = 0; i < DocID_times.Rows.Count; i++)
{
j = i + 1;
if (i < (DocID_times.Rows.Count - 1))
{
DateTime tempo1 = DateTime.ParseExact(DocID_times.Rows[i]["Time"].ToString(), "dd-MM-yyyy HH:mm:ss",
System.Globalization.CultureInfo.InvariantCulture);
DateTime tempo2 = DateTime.ParseExact(DocID_times.Rows[j]["Time"].ToString(), "dd-MM-yyyy HH:mm:ss",
System.Globalization.CultureInfo.InvariantCulture);
double mins = (tempo2 - tempo1).TotalMinutes;
TimeSpan result = TimeSpan.FromMinutes(mins);
double days = result.TotalDays;
var rows = times.Select(string.Format("DepartmentID = {0} AND DocID = {1}", DepartmentID, DocID));
if (rows.Length == 0)
{
// Add your Row
times.Rows.Add(DepartmentID, DocID, days);
}
else
{
// Update your Days
rows[0]["days"] = Convert.ToInt32(rows[0]["days"].ToString()) + days;
}
}
}
}
If you're listing all the rows, I would calculate the days between records inside a while loop. It can be done purely with SQL, but it won't be as good as the while loop (which can have access to two rows at a time). To be able to do it purely in SQL, you would have to join the table with itself, joining each record with the next one.
IEnumerable<MySummarizedRow> GetSummarizedRows()
{
using (var entries = GetRowsOrderedByDocIdAndRowId().GetEnumerator())
{
if (entries.MoveNext())
{
var previous = entries.Current;
while (entries.MoveNext())
{
var current = entries.Current;
if (current.DocId == previous.DocId)
yield return new MySummarizedRow(previous.DepartmentId, current.DocId, current.Time.Substract(previous.Time).TotalDays + 1);
previous = current;
}
}
}
}
This function ignores the rows for a document that hasn't been passed to another department yet. You can easily change that yielding a new row with -1 days or something like that.

How to sum/group by rows that w/ hour format(120:15:10) in C# like in SQL - SELECT SUM (col1), col 2, col3 GROUP BY col2, col3

Problem:
I have a sql database with C# widowsform app with datagridview to show results.
I import data from csv with streamreader.
And I need to make a SELECT SUM([col1]), [col2], [col3] GROUP BY [col2], [col3]
But the column that I need to SUM is nvarchar representing Hours that have the format "000:00:00"
Example:
DB columns:
occurrence_number|solution_group|timein_sgroup
SQL Comamand:Select sum(timein_sgroup), occurence_number, solution_group Group by occurence_number, solution_group
resume: I need the sum of hours in a column(occurence_number) with results grouped by two columns(occurence_number and solution_group)
It's a system that calculates the total time that a support group stayed working with/in the occurrence.
I need a result like this = how much hours an occurence stayed with in a solution group:
occnum | groupnamelvl | total hours(SUM)
------------------------------------------
occ001 | sgrouplevel2 | 120:10:10
occ002 | sgrouplevel1 | 20:30:15
occ001 | sgrouplevel1 | 05:15:00
occ010 | sgrouplevel3 | 105:05:00
I saw a lot of topics about sum Hour showing a result with more than 24 hours but the solutions does not work when i have alredy a column with rows data like this:
occnum | groupnamelvl | hours to sum
------------------------------------------
occ001 | sgrouplevel2 | 120:15:10
occ001 | sgrouplevel2 | 30:10:40
occ001 | sgrouplevel2 | 110:30:00
How to sum this column and show result like:
occnum | groupnamelvl | Total_Hours
------------------------------------------
occ001 | sgrouplevel2 | 260:55:50
I use this but its only work with data mior tahn 24h and the result can bem more than 24 but minor than 99:
SELECT CONVERT(NVARCHAR,
DATEADD(Minute,
SUM(
DATEPART(SECOND,CONVERT(datetime,[colunm],8)) + 60 *
DATEPART(MINUTE,CONVERT(datetime,[colunm],8)) + 3600 *
DATEPART(HOUR,CONVERT(datetime,[colunm],8))
) /60, '00:00:00'), 108) AS [TOTAL] FROM tb
C# part with query:
Database1DataSet ds = new Database1DataSet();
string strSQL = "that query";
SqlCeConnection conn = new SqlCeConnection(#"Data Source=\App_sqlce35\App\DATA\Database1.sdf");
SqlCeDataAdapter da = new SqlCeDataAdapter(strSQL, conn);
try
{
conn.Open();
ds.Tables.Add("historico");
ds.Tables["historico"].BeginLoadData();
da.Fill(ds.Tables["historico"]);
ds.Tables["historico"].EndLoadData();
tb_histstatusDataGridView.DataSource = ds.Tables["historico"];
New code with help from #AsadAli works fine but i can´t group by:
SqlCeConnection conn = new SqlCeConnection(#"Data Source=\App_sqlce35\DATA\Database1.sdf");
SqlCeCommand cmdselect = new SqlCeCommand("select [col0], [col1], [col2], from tb_histstatus WHERE [col6] <>'';", conn);
try
{
conn.Open();
SqlCeDataReader res = cmdselect.ExecuteReader();
List<string> times = new List<string>();
while (res.Read())
{
times.Add((string)res.GetValue(2));
}
int[] result = new int[3];
foreach (string time in times)
{
string[] parts = time.Split(':');
for (int i = 0; i < parts.Length; i++)
{
result[i] += Convert.ToInt32(parts[i]);
}
}
TimeSpan ts = TimeSpan.FromSeconds(result[1] * 60 + result[2]);
result[0] += ts.Hours; result[1] = ts.Minutes; result[2] = ts.Seconds;
string resultString = string.Join(":", result);
MessageBox.Show("Total: " + resultString);
}
Here is an example of what I'd do:
int[] result = new int[3]; //Assuming the format is always as in OP
string[] times = { "120:15:10", "30:10:40", "110:30:00" };
foreach (string time in times)
{
string[] parts = time.Split(':');
for (int i = 0; i < parts.Length; i++)
{
result[i] += Convert.ToInt32(parts[i]);
}
}
TimeSpan ts = TimeSpan.FromSeconds(result[1] * 60 + result[2]);
result[0] += ts.Hours; result[1] = ts.Minutes; result[2] = ts.Seconds;
string resultString = string.Join(":", result);
Output: 260:55:50
Edit: I've updated my code to match the correct format.
Edit 2: Here's how you'd use it.
SqlCeConnection conn = new SqlCeConnection(#"Data Source=\App_sqlce35\DATA\Database1.sdf");
SqlCeCommand cmdselect = new SqlCeCommand("select [col0], [col1], [col2], [col3], [col4], [col5], [col6] from tb_histstatus WHERE [col6] <>'';", conn);
try
{
conn.Open();
SqlCeDataReader res = cmdselect.ExecuteReader();
List<string> times = new List<string>();
while (res.Read()) {
times.Add((string)res.GetValue(6));
}
int[] result = new int[3];
foreach (string time in times)
{
string[] parts = time.Split(':');
for (int i = 0; i < parts.Length; i++)
{
result[i] += Convert.ToInt32(parts[i]);
}
}
TimeSpan ts = TimeSpan.FromSeconds(result[1] * 60 + result[2]);
result[0] += ts.Hours; result[1] = ts.Minutes; result[2] = ts.Seconds;
string resultString = string.Join(":", result);
MessageBox.Show("Total: " + resultString);
}
I think you have choosed the wrong datatype for your column. Instead of storing these values as strings or datetime you could simply use an integer column where you store just the total of seconds.
260:50:55 = (260*60*60) + (50 * 60) + 55 = 939350 seconds.
Now you have a perfectly manageable value for SUM aggregate function.
Just when you need to show the value you apply the formula to separate the part values
int seconds = GetDurationFromDatabase(); // IE=939350;
TimeSpan ts = new TimeSpan(0,0,seconds);
Console.WriteLine("{0}:{1}:{2}", ts.Days * 24 + ts.Hours, ts.Minutes, ts.Seconds);
public static void TimeCalc()
{
string[] t1 = "120:15:10".Split(':');
string[] t2 = "30:10:40".Split(':');
string[] t3 = "110:30:00".Split(':');
TimeSpan ts1 = new TimeSpan(Convert.ToInt32(t1[0]), Convert.ToInt32(t1[1]), Convert.ToInt32(t1[2]));
TimeSpan ts2 = new TimeSpan(Convert.ToInt32(t2[0]), Convert.ToInt32(t2[1]), Convert.ToInt32(t2[2]));
TimeSpan ts3 = new TimeSpan(Convert.ToInt32(t3[0]), Convert.ToInt32(t3[1]), Convert.ToInt32(t3[2]));
TimeSpan ts = ts1.Add(ts2).Add(ts3);
Console.WriteLine((ts.Hours + (ts.Days * 24)).ToString() + ":" + ts.Minutes.ToString() + ":" + ts.Seconds.ToString());
}
This works. Kind of not elegant, but works...
Pretend that "times": is a list of strings[], then you can do something like this:
string[] t1 = "120:15:10".Split(':');
string[] t2 = "30:10:40".Split(':');
string[] t3 = "110:30:00".Split(':');
List<string[]> times = new List<string[]>();
times.Add(t1);
times.Add(t2);
times.Add(t3);
TimeSpan ts = new TimeSpan();
foreach (var item in times)
{
TimeSpan tsa = new TimeSpan(Convert.ToInt32(item[0]), Convert.ToInt32(item[1]), Convert.ToInt32(item[2]));
ts = (ts == TimeSpan.Zero) ? tsa : ts.Add(tsa);
}
Console.WriteLine((ts.Hours + (ts.Days * 24)).ToString() + ":" + ts.Minutes.ToString() + ":" + ts.Seconds.ToString());

How to return 0 if null then import to datagridview

I've got a sql data like this
1 2m
2 3m
3 3m
6 6m
7 6m
I want to export and show it into datagridview.
1 2m
2 3m
3 3m
4 0m
5 0m
6 6m
7 6m
And here is my code:
private void laygio(string tenstore, string tenxuat)
{
string conn = "Data Source=USER-PC;Initial Catalog=NCKHmoi;Integrated Security=True";
SqlConnection connect = new SqlConnection(conn);
SqlCommand command = new SqlCommand();
command.Connection = connect;
connect.Open();
int stday = Convert.ToInt32(dst.Text);
int stmonth = Convert.ToInt32(mst.Text);
int styear = Convert.ToInt32(yst.Text);
int sthour = Convert.ToInt32(hst.Text);
int stminute = 0;
int stsecond = 0;
int eday = Convert.ToInt32(ded.Text);
int emonth = Convert.ToInt32(med.Text);
int eyear = Convert.ToInt32(yed.Text);
int ehour = Convert.ToInt32(hed.Text);
int eminute = 0;
int esecond = 0;
DateTime startday = new DateTime(styear, stmonth, stday, sthour, stminute, stsecond);
DateTime endday = new DateTime(eyear, emonth, eday, ehour, eminute, esecond);
DataTable tbl = new DataTable();
DataColumn Col = new DataColumn("Thời gian", typeof(int));
tbl.Columns.Add(Col);
SqlDataAdapter adapter = new SqlDataAdapter();
int i = 1;
for (DateTime xday = startday; xday <= endday; xday += TimeSpan.FromHours(1))
{
int ngay = Convert.ToInt32(xday.Day.ToString());
int thang = Convert.ToInt32(xday.Month.ToString());
int nam = Convert.ToInt32(xday.Year.ToString());
int gio = Convert.ToInt32(xday.Hour.ToString());
command.CommandType = CommandType.Text;
command.CommandText = #"Select SoLieuGio.LLNuoc from SoLieuGio where SoLieuGio.GioID= (select Gio.GioID from Gio where (Gio.Gio = #Gio and Gio.NgayID= (select Ngay.NgayID from Ngay where (Ngay.Ngay=#Ngay and Ngay.ThangID= (select Thang.ThangID from Thang where (Thang.Thang = #Thang and Thang.NamID=(select Nam.NamID from Nam where (Nam.Nam = #Nam and Nam.TramID=(select Tram.TramID from Tram Where (Tram.TenTram like #TenTram and Tram.TinhID=(select Tinh.TinhID from Tinh where (Tinh.TenTinh like #TenTinh and Tinh.KhuVucID=(select KhuVuc.KhuVucID from KhuVuc where KhuVuc.Ten=#Ten)))))))))))))";
command.Parameters.Add("#Gio", SqlDbType.BigInt).Value = gio;
command.Parameters.Add("#Ngay", SqlDbType.BigInt).Value = ngay;
command.Parameters.Add("#Thang", SqlDbType.BigInt).Value = thang;
command.Parameters.Add("#Nam", SqlDbType.BigInt).Value = nam;
command.Parameters.Add("#Ten", SqlDbType.NVarChar, 50).Value = "Đồng Bằng Bắc Bộ";
command.Parameters.Add("#TenTinh", SqlDbType.NVarChar, 50).Value = TinhComboBoxEx.Text;
command.Parameters.Add("#TenTram", SqlDbType.NVarChar, 50).Value = TramComboBoxEx.Text;
adapter.SelectCommand = command;
adapter.Fill(tbl);
dataGridView2.DataSource = tbl;
command.Parameters.Clear();
}
command.Dispose();
connect.Close();
}
The result of that code is:
1 2m
2 3m
3 3m
6 6m
7 6m
What need i fix to show it fully from 1 to 7.
You could use the tally table master..spt_values to deal with missing items in your series.
You do this by left joining to your tables and coalesce your values.
For example
CREATE TABLE ATable
([Number] int, [value] varchar(2))
;
INSERT INTO ATable
([Number], [value])
VALUES
(1, '2m'),
(2, '3m'),
(3, '3m'),
(6, '6m'),
(7, '6m')
;
This
SELECT
v.Number,
COALESCE(ATable.Value, '0m') Value
FROM
master..spt_values v
LEFT JOIN ATable
ON v.Number = ATable.Number
WHERE
v.Type = 'P'
and v.Number > 0 and v.Number < 8
Will produce this value
| NUMBER | VALUE |
------------------
| 1 | 2m |
| 2 | 3m |
| 3 | 3m |
| 4 | 0m |
| 5 | 0m |
| 6 | 6m |
| 7 | 6m |
DEMO
the easiest thing to do in this case I think is to check everytime if the current value is the sum of the previous value + 1
if (current != (previous + 1)
{
//make new 4 0m or something
}
else
{
//continue reading
}
Try creating a temporary table that will hold missing values and then join main table and temporary table.
This is how it could look like
create table #temp1
(
ID int identity(1,1),
M varchar(4)
)
declare #count int
SET #count = 0
declare #max int
SET #max = 20
while #count < #max
begin
insert into #temp1 (M) values ('0m')
SET #count = #count + 1
end
select * from #temp1
select (case M1.ID when null then T1.ID else M1.ID) as ID,
(case M1.M when null then T1.M else M1.ID) as TXT
from MainTable M1
join #temp1 T1
order by ID

Categories

Resources