![](/img/trans.png)
[英]from existing value Update column using comma-separated values in SQL Server
[英]Need to update a column in SQL with WHERE using comma separated values from textbox
只是想讓你們知道我不是程序員@all 但有時我可以設法讓代碼工作但我現在很難過。 我有一個 c# 基於 Web 的項目,我終於想出了如何在單擊搜索時從單個文本框傳遞逗號分隔值以在 Datagrid 中返回結果。 代碼如下所示:
{
String str = "select row_number() OVER (ORDER BY [sequenceid]) #,[JobNumber],[Item],Quantity,Bay,Trailer,Sequenceid, Produced from vwcabsandcountersbyjob ";
String str1 = "select SUM([Quantity])AS [Items Remaining to Be Loaded] from vwcabsandcountersbyjob";
//CODE THAT ALLOWS MULTIPLE ORDER NUMBERS TO BE ENTERED IN A SINGLE TEXTBOX
if (!string.IsNullOrEmpty(TextBox1.Text.Trim()))
{
List<string> search = new List<string>();
char[] characters = { ',', '\n' };
string[] ids = TextBox1.Text.Trim().Split(characters, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < ids.Length; i++)
{
search.Add(ids[i].Trim());
}
str += " WHERE (jobnumber IN ('" + string.Join("','", search.ToArray()) + "') and loaded is null) ORDER BY ITEM DESC";
}
//CODE THAT ALLOWS MULTIPLE ORDER NUMBERS TO BE ENTERED IN A SINGLE TEXTBOX
if (!string.IsNullOrEmpty(TextBox1.Text.Trim()))
{
List<string> search = new List<string>();
char[] characters = { ',', '\n' };
string[] ids = TextBox1.Text.Trim().Split(characters, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < ids.Length; i++)
{
search.Add(ids[i].Trim());
}
str1 += " WHERE (jobnumber IN ('" + string.Join("','", search.ToArray()) + "') and loaded is null) ";
}
SqlCommand xp = new SqlCommand(str, vid);
SqlCommand xp1 = new SqlCommand(str1, vid);
//xp.Parameters.Add("@search", SqlDbType.NVarChar).Value = TextBox1.Text;
xp.Parameters.Add("@search", SqlDbType.NVarChar, 20).Value = TextBox1.Text;
xp1.Parameters.Add("@search", SqlDbType.NVarChar).Value = TextBox1.Text;
vid.Open();
xp.ExecuteNonQuery();
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = xp;
DataSet ds = new DataSet();
da.Fill(ds, "[jobnumber]");
GridView1.DataSource = ds;
GridView1.DataBind();
vid.Close();
vid.Open();
xp1.ExecuteNonQuery();
SqlDataAdapter da1 = new SqlDataAdapter();
da1.SelectCommand = xp1;
DataSet ds1 = new DataSet();
da1.Fill(ds1, "[jobnumber]");
GridView2.DataSource = ds1;
GridView2.DataBind();
vid.Close();
}
現在我有第二個按鈕,當他們按下“標記完成”時,我想更新一個字段。 它適用於單個條目,這是代碼:
protected void Button2_Click(object sender, EventArgs e)
{
vid.Open();
SqlCommand xp = new SqlCommand("Update [Job_Master] SET [Completed] = GETDATE() WHERE [job number] =@search", vid);
SqlCommand xp3 = new SqlCommand("Update [Countertops] SET [Completed] = GETDATE() WHERE [jobnumber] =@search", vid);
xp.Parameters.Add("@search", SqlDbType.VarChar).Value = TextBox1.Text;
xp3.Parameters.Add("@search", SqlDbType.NChar).Value = TextBox1.Text;
xp.ExecuteNonQuery();
xp3.ExecuteNonQuery();
vid.Close();
string message = "This job has been marked complete!";
string script = "window.onload = function(){ alert('";
script += message;
script += "')};";
ClientScript.RegisterStartupScript(this.GetType(), "SuccessMessage", script, true);
}
問題是它只適用於一個值。 我已經嘗試了一百萬種不同的方法,但沒有任何效果,主要是因為我不知道自己在做什么。 這是我最接近的(我添加了第三個按鈕,因為我不想破壞適用於單個值的按鈕 2):
Protected void Button3_Click(object sender, EventArgs e)
{
String str3 = "Update [Job_Master] SET [Completed] = GETDATE()";
if (!string.IsNullOrEmpty(TextBox1.Text.Trim()))
{
List<string> search = new List<string>();
char[] characters = { ',', '\n' };
string[] ids = TextBox1.Text.Trim().Split(characters, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < ids.Length; i++)
{
search.Add(ids[i].Trim());
}
str3 += " WHERE [job number] IN ('" + string.Join("','", search.ToArray()) + "')";
}
SqlCommand xp4 = new SqlCommand(str3, vid);
vid.Open();
xp4.Parameters.Add("@search", SqlDbType.VarChar).Value = TextBox1.Text;
xp4.ExecuteNonQuery();
vid.Close();
string message = "This job has been marked complete!";
string script = "window.onload = function(){ alert('";
script += message;
script += "')};";
ClientScript.RegisterStartupScript(this.GetType(), "SuccessMessage", script, true);
}
它不起作用。 它僅在我有一個條目時更新。 我的問題是如何在更新語句中使用該文本框中的相同值? 我希望我說得很清楚,但會盡力回答任何問題,但請記住,在編程方面,我的詞匯量非常有限。 謝謝!
明智的做法是將代碼分成更小的部分,並按它們的角色和職責對它們進行分組。 這將使事情更容易維護和使用。
如果您看到重復的代碼,那么這是將其移至單獨方法的標志。
我在您的代碼中發現的一些注意事項:
using
子句,例如將它與SqlConnection
、 SqlCommand
和SqlDataAdapter
一起使用。SqlCommand
。SqlParamter
。StringBuilder
。Split
返回Array
,因此無需將Array
轉換為另一個Array
。OnClick
事件,應該只處理點擊事件,不處理更新記錄。 更新部分應該在事件外部聲明和處理,您只能從事件內部調用它。我已經更新了代碼,這將使您更好地了解上述注釋:
protected void SearchButton_OnClick(object sender, EventArgs args)
{
//CODE THAT ALLOWS MULTIPLE ORDER NUMBERS TO BE ENTERED IN A SINGLE TEXTBOX
if (!string.IsNullOrWhiteSpace(TextBox1.Text))
{
SearchAndBind(TextBox1.Text);
}
}
protected void Button2_Click(object sender, EventArgs e)
{
var textValue = TextBox1.Text.Trim();
if(!string.IsNullOrWhiteSpace(textValue))
{
UpdateRecords("UPDATE [Job_Master] SET [Completed] = GETDATE() WHERE [job number] = @search", "@search", textValue);
UpdateRecords("UPDATE [Countertops] SET [Completed] = GETDATE() WHERE [jobnumber] = @search", "@search", textValue);
CompletedJobNotification();
}
}
protected void Button3_Click(object sender, EventArgs e)
{
string inClause = GetInClause(TextBox1.Text);
if(!string.IsNullOrWhiteSpace(inClause))
{
StringBuilder query = new StringBuilder("Update [Job_Master] SET [Completed] = GETDATE()");
query.Append(" WHERE [job number] ").Append(inClause);
UpdateRecords(query.ToString());
CompletedJobNotification();
}
}
private void PopulateData(string query, string srcTable, GridView gridView)
{
if (!string.IsNullOrWhiteSpace(query))
{
using(SqlConnection connection = new SqlConnection(connectionString))
using(SqlDataAdapter adapter = new SqlDataAdapter(query, connection))
{
adapter.Open();
DataSet ds = new DataSet();
da.Fill(ds, srcTable);
gridView.DataSource = ds;
gridView.DataBind();
}
}
}
private string GetInClause(string text)
{
if(!string.IsNullOrWhiteSpace(text))
{
char[] characters = { ',', '\n' };
var ids = text.Trim().Split(characters, StringSplitOptions.RemoveEmptyEntries);
return "IN ('" + string.Join("','", ids) + "')";
}
return string.Empty;
}
private void SearchAndBind(string search)
{
//CODE THAT ALLOWS MULTIPLE ORDER NUMBERS TO BE ENTERED IN A SINGLE TEXTBOX
if (!string.IsNullOrWhiteSpace(search))
{
string inClause = GetInClause(search);
if(!string.IsNullOrWhiteSpace(inClause))
{
var searchWhere = $" WHERE jobnumber loaded IS NULL AND {inClause} ";
StringBuilder str = new StringBuilder("SELECT ROW_NUMBER() OVER (ORDER BY [sequenceid]) #,[JobNumber],[Item],Quantity,Bay,Trailer,Sequenceid, Produced FROM vwcabsandcountersbyjob");
StringBuilder str1 = new StringBuilder("SELECT SUM([Quantity]) AS [Items Remaining to Be Loaded] FROM vwcabsandcountersbyjob");
str.Append(searchWhere).Append(" ORDER BY ITEM DESC ");
str1.Append(searchWhere);
PopulateData(str.ToString(), "[jobnumber]", GridView1);
PopulateData(str1.ToString(), "[jobnumber]", GridView2);
}
}
}
private void UpdateRecords(string query, string parameterName = null,string parameterValue = null)
{
using(var connection = new SqlConnection(connectionString))
using(var command = new SqlCommand(query))
{
if(!string.IsNullOrWhiteSpace(parameterName) && !string.IsNullOrWhiteSpace(parameterValue))
{
command.Parameters.AddWithValue(parameterName, parameterValue);
}
connection.Open();
command.ExecuteNonQuery();
}
}
private void ShowJavaScriptAlert(string message)
{
if(!string.IsNullOrWhiteSpace(inClause))
{
ClientScript.RegisterStartupScript(this.GetType(), "SuccessMessage", $" window.onload = function(){{ alert('{message}')}}; ", true);
}
}
private void CompletedJobNotification()
{
ShowJavaScriptAlert("This job has been marked complete!");
}
好的,首先,我們在這里寫了太多代碼。
接下來,我們可以肯定地擁有一個參數列表,它們可以是可選的,並且我們永遠不會將用戶輸入連接到 SQL 字符串中——我們不必這樣做。
現在,我沒有用戶數據,讓我們這樣做:
我可以輸入一個或幾個城市。 我會顯示一些酒店,然后一個按鈕來確認酒店並用確認日期更新數據庫。
(與您正在做的一樣)。
好的,所以有一個文本框和一個按鈕。 像這樣:
Search: <asp:TextBox ID="txtPromptCity" runat="server" Height="17px" Width="336px"></asp:TextBox>
<asp:Button ID="cmdSearch" runat="server" Text="Search City" Style="margin-left:20px" />
因此,您可以輸入一個或多個城市(中間有一個)。 與您需要/正在做的一樣。
好的,所以當您輸入並點擊搜索時,我們會將結果發送到網格視圖。
所以,我們有這個按鈕代碼:
DataTable rstHotels = new DataTable();
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
rstHotels = (DataTable)ViewState["rstHotels"];
}
protected void cmdSearch_Click(object sender, EventArgs e)
{
string[] strChoices;
strChoices = txtPromptCity.Text.Split(',');
using (SqlCommand cmdSQL = new SqlCommand("",
new SqlConnection(Properties.Settings.Default.TEST4)))
{
string strSQL = "";
int i = 1;
foreach (string strCity in strChoices)
{
if (strSQL != "")
strSQL += ",";
i += 1;
strSQL += "@" + i;
cmdSQL.Parameters.Add("@" + i, SqlDbType.NVarChar).Value = strCity;
}
cmdSQL.CommandText = "SELECT * from tblHotels WHERE City IN (" + strSQL + ")";
cmdSQL.Connection.Open();
rstHotels.Rows.Clear();
rstHotels.Load(cmdSQL.ExecuteReader());
ViewState["rstHotels"] = rstHotels;
GridView1.DataSource = rstHotels;
GridView1.DataBind();
}
}
請注意我如何保留/擁有 data.table - 我將其保留在 class 級別。
所以,我們的 output 現在是這個
好的,所以我們現在有參數問題了。
現在,您所要做的就是選中要批准的那些,然后將數據連同批准的訪問日期一起發送回表格。
該代碼現在變得非常簡單。
我們可以使用這個:
protected void cmdConfirm_Click(object sender, EventArgs e)
{
foreach (GridViewRow gvRow in GridView1.Rows)
{
CheckBox chkVisit = (CheckBox)gvRow.FindControl("chkVisit");
if (chkVisit.Checked)
// update Visit date in table
rstHotels.Rows[gvRow.RowIndex]["VistDate"] = DateTime.Today;
// now send table changes back to database.
using (SqlCommand cmdSQL = new SqlCommand("SELECT * from tblHotels where ID = 0",
new SqlConnection(My.Settings.TEST4)))
{
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder daUpate = new SqlCommandBuilder(da);
da.Update(rstHotels);
}
}
}
因此,請注意我們如何將網格選擇發送回表,然后將表發送回數據庫。 這使得整個過程變得簡單,代碼也少得多。
我可能會在 Row 綁定事件中添加 2-3 行代碼,如果該行已經有日期,則設置復選框。 我什至可以假設我們是否取消選中復選框,然后再次在日期列行中顯示 null。
使用上述方法,所有這些都非常容易。
因此,按照上面的方式保留表格 - 這真的很容易。 並注意數據鍵設置——我們可以使用/獲取/獲取每一行的主鍵,而不必顯示它——但這個例子無論如何都不需要這種能力。
我在上面使用的標記是這樣的:
Search: <asp:TextBox ID="txtPromptCity" runat="server" Height="17px" Width="336px"></asp:TextBox>
<asp:Button ID="cmdSearch" runat="server" Text="Search City" Style="margin-left:20px" OnClick="cmdSearch_Click" />
<div style="width:45%;margin-top:20px;margin-left:20px">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table table-hover">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="VistDate" HeaderText="Visit Date" DataFormatString="{0:yyyy-MM-dd}" />
<asp:TemplateField HeaderText="Confirm Visit" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chkVisit" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="cmdConfirm" runat="server" Text="Confirm Vists" Width="143px" CssClass="btn-info" OnClick="cmdConfirm_Click" />
<br />
</div>
感謝大家的幫助。 實際是我的 aspx 代碼指向 OnClick="Button2_Click" 而不是 OnClick="Button3_Click"。 一旦我修復了它並放入原始代碼,它就可以工作了。 話雖如此,你們已經指出了一些我要嘗試修復的要點。 再說一遍,我不是程序員,非常感謝你們的幫助。 謝謝。
首先,盡你所能。 我認為唯一剩下的只是一個簡單的錯誤。 我會提供這個刪除一些你不需要的代碼
Protected void Button3_Click(object sender, EventArgs e)
{
String str3 = "Update [Job_Master] SET [Completed] = GETDATE()";
// ** This is a little dangerous. If the TextBox is EMPTY, you will be
// ** Updating ALL rows in the table. I assume that is not what you want.
// ** You should return an error if text box is empty.
if (!string.IsNullOrEmpty(TextBox1.Text.Trim()))
{
char[] characters = { ',', '\n' };
char[] invalid = { ',',';',' ','\'','"','\\','\t' };
string[] ids = TextBox1.Text.Trim().Split(characters, StringSplitOptions.RemoveEmptyEntries);
//
// ** You don't really need to copy into a list.
// ** If you want to trim each entry, you can just
// ** replace in the original array.
for (int i = 0; i < ids.Length; i++)
{
ids[i] = ids[i].Trim();
// ** Add a check here to make sure id is safe
// ** to prevent SQL injection.
if (ids[i].IndexOfAny( invalid ) != -1)
{
return; // should give error, probably.
}
}
// *** figure out if it is job_number or jobnumber or (unlikely) job number
str3 += " WHERE [job_number] IN ('" + string.Join("','", ids) + "')";
}
else {
return; // empty string. Should give error.
}
// ** OPEN FIRST
vid.Open();
SqlCommand xp4 = new SqlCommand(str3, vid);
// ** @search not needed
// xp4.Parameters.Add("@search", SqlDbType.VarChar).Value = TextBox1.Text;
xp4.ExecuteNonQuery();
vid.Close();
string message = "This job has been marked complete!";
string script = "window.onload = function(){ alert('";
script += message;
script += "')};";
ClientScript.RegisterStartupScript(this.GetType(), "SuccessMessage", script, true);
}
現在,如果 ID 不應該是數字,則防止 SQL 注入會有點困難。 您希望為每個參數(@1、@2、@3 等)創建一個參數並將每個參數添加為參數。
或者,當然,您可以為每個 ID 運行單獨的 SQL 語句。 不是超級高效但可能足夠快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.