DataTable 查詢、新增欄位、計算總數

當我們在建立一個 DataTable 時,有時會在後端程式碼撰寫增加欄位或是計算欄位裡面的一些數字總和,

以及像是查詢的條件等,要如何撰寫呢?

以上一篇 <DataTable 欄位加總>的例子為例,下方為資料表中的原始欄位與資料,當我們今天要多加一欄位

來計算 Total 的總數時,必須用到增加欄位及計算總數的方法;

而在查詢的部分,當我們頁面上有多的CheckBoxList選項時,我們查詢也許不只一個,有多個的情況,此時要透過程式撰寫及SQL指令的方式將條件寫好,

在下SQL指令來串字串時,要小心有關在串字串的同時,一些條件的關鍵字或是擺放位置,甚至是數量,

參考以下程式碼:

//命名空間
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;

...
以下省略

//資料庫連線設定
SqlConnection conn = new SqlConnection
        (ConfigurationManager.ConnectionStrings["TestConnectionString"].ConnectionString);


protected void Page_Load(object sender, EventArgs e)
{
     if (starttime.Text.Trim() != "" && endtime.Text.Trim() != "") 
         // 在前端頁面中,放置兩個 TextBox 控制項,以便用來作為查詢的起迄日條件
     {
        conn.open();
        DataTable P = new DataTable(); //新增表P來存放資料
        List<string> ch = new List<string>(); //新建 List 來作為 SQL 條件查詢的迴圈判斷
        string sql = @"select channel,SUM(total) from test where channel not like '%600K%' 
        and time between @stime and @etime ";//查詢條件,選取非_600K的頻道
        
        if (!channel.Items[0].Selected)// 判斷在組合SQL字串時,加 ()、and、or 的位置與數量
     {
        sql += "and ( ";

        foreach (ListItem item in channel.Items)
        {
         if (item.Selected)
         ch.Add(item.Value);
        }
         
        for (int i = 0; i < ch.Count; i++)//計算要放入幾個 or ,最後一個字串後方不加入 or
        {
         sql += "channel like '" + ch[i].ToString() + "' ";
         if (i < ch.Count - 1)
         sql += "or ";
        }
         sql += ")";
        
     }
        sql += " group by channel order by channel";                            
        SqlDataAdapter name_2 = new SqlDataAdapter(sql,conn);
        name_2.SelectCommand.Parameters.Add("@stime", SqlDbType.NVarChar).Value = starttime.Text;
        name_2.SelectCommand.Parameters.Add("@etime", SqlDbType.NVarChar).Value = endtime.Text;
        name_2.Fill(P);
     }        


        //選取只有 _600K 的頻道以及扣掉fish、twgoodmusic、twglive、chlive 四個頻道 (作法如同上面一樣)
        DataTable G = new DataTable();
        List<string> ch_1 = new List<string>();
        string sql_1 = @"select channel,SUM(total) from test where channel like '%600K%' 
        and time between @stime and @etime ";
        if (!channel.Items[0].Selected)
        {
          sql_1 += "and ( ";
          foreach (ListItem item in channel.Items)
        {
        if (item.Selected)
        ch_1.Add(item.Value);
        }
        for (int i = 0; i < ch_1.Count; i++)
        {
        sql_1 += "channel like '" + ch_1[i].ToString() + "'";
        if (i < ch_1.Count - 1)
        sql_1 += "or ";
        }
        sql_1 += ")";
        }
        sql_1 += " group by channel order by channel";
        SqlDataAdapter name_5 = new SqlDataAdapter(sql_1, conn);
        name_5.SelectCommand.Parameters.Add("@stime", SqlDbType.NVarChar).Value = starttime.Text;
        name_5.SelectCommand.Parameters.Add("@etime", SqlDbType.NVarChar).Value = endtime.Text;
        name_5.Fill(G);
}

而接下來要對 DataTable 做增加欄位與加總,這裡有兩種狀況:

(1)若是先做加總再排序的話,則頁面讀取時會連同"加總的欄位"部分一起做排序。

(2)若是先做排序再加總的話,則"加總的欄位"部分就不會被移動到。

今天我們要的是第二種狀況,參考以下程式碼(接續上面部分):

M = P.Clone(); //複製表P的架構,不會有任何的DataRows 
foreach (DataRow dr in P.Select("1=1", "Total desc")) // ()內前方為條件式,後方為判斷欄位
{
M.ImportRow(dr);//表M中添加一個新行,並將dr的值複製進去,要求的資料表格式一樣
}
P.Clear();//將表P的內容清除

DataRow workRow = M.NewRow(); //增加兩個欄位存放 "總計"、"數目的總數"

int value_1 = 0;
for (int f = 0; f < M.Rows.Count; f++) 
{
value_1 = value_1 + int.Parse(M.Rows[f][1].ToString()); //Total的數目加總
}
workRow[0] = "總計";
workRow[1] = value_1;
M.Rows.Add(workRow);


//在 GridView 中動態新增一個欄位,給予編號
M.Columns.Add("NO", typeof(string));
M.Columns["NO"].SetOrdinal(0);  //指定 NO 這個欄位放在表的第一欄                      
for (int v = 0; v < M.Rows.Count; v++)//加入編號
{
M.Rows[v][0] = v + 1;
}                          
 conn.Close();
 GridView1.DataSource = M;
 GridView1.DataBind();