Populate Datatable - Row with Data from Sql-Command with several selectquery - c#

I have the following function:
private static DataTable GetDataFromDatabase(DateTime myDate)
{
DataTable table = new DataTable();
table.Columns.AddRange(new DataColumn[]
{
new DataColumn("Event"), new DataColumn("Room"),
new DataColumn("From"), new DataColumn("To"), new DataColumn("Persons"),
new DataColumn("Equipment"), new DataColumn("Catering")
});
string strSQL = "SELECT distinct ID FROM VIEW_RAUMBUCHUNG_DISPO " +
"WHERE BOOKSTATUS >= 1 AND convert(char, von,104) = '" +
BookITVbSQL.to_104(myDate) + "'";
SqlDataReader objRS;
objRS = SQLrunReaderDP(strSQL);
while (objRS.Read())
{
using (SqlConnection con = new SqlConnection(GetConnectionString()))
{
using (SqlCommand cmd = con.CreateCommand())
{
con.Open();
cmd.CommandText = "SELECT distinct EVENT, ROOM, CONVERT(char(5), from, 108) " +
"FROM, CONVERT(char(5), to, 108) TO, PERSONS FROM VIEW_RAUMBUCHUNG_DISPO " +
"WHERE ID = '" + objRS["ID"] + "'; " +
"SELECT EQUIPMENTNAME FROM EQUIPMENT WHERE BUCHUNG_ID = '" + objRS["ID"] +
"' and STATUS = '2'; " +
"SELECT CATERINGNAME FROM CATERING WHERE BUCHUNG_ID = '" + objRS["ID"] +
"' and STATUS = '1';";
using (SqlDataReader rdr = cmd.ExecuteReader())
{
do
{
while (rdr.Read())
{
table.Rows.Add(
rdr["EVENT"],
rdr["ROOM"],
rdr["FROM"],
rdr["TO"],
rdr["PERSONS"] );
}
}
while (rdr.NextResult());
rdr.Close();
}
con.Close();
}
}
}
return table;
}
This works fine for the first Statement. I can get all the Data from the five Columns.
But how can i Add the Columns from the other two Querys to the same Row?
If i try:
while (rdr.Read())
{
table.Rows.Add(
rdr["EVENT"],
rdr["ROOM"],
rdr["FROM"],
rdr["TO"],
rdr["PERSONS"],
rdr["EQUIPMENTNAME"]);
}
so iam getting an IndexOutOfRange - Exception.
Can someone help me with that please?

SqlDataReader class:
Provides a way of reading a forward-only stream of rows from a SQL Server database.
You can use this class make a single statement with 2 joins. It will return 7 columns
"SELECT distinct EVENT, ROOM, CONVERT(char(5), from, 108) FROM, CONVERT(char(5), to, 108) TO, PERSONS, EQUIPMENTNAME, CATERINGNAME FROM VIEW_RAUMBUCHUNG_DISPO T1"
+ "INNER JOIN (SELECT EQUIPMENTNAME FROM EQUIPMENT) T2 ON T1.ID = T2.BUCHUNG_ID"
+ "INNER JOIN (SELECT CATERINGNAME FROM CATERING) T3 ON T1.ID = T3.BUCHUNG_ID" +
+ "WHERE T1.ID = '" + objRS["ID"] + "' AND T2.STATUS = '2' AND T3.STATUS = '1' "
UPDATE
Use NextResult method:
Advances the data reader to the next result, when reading the results of batch Transact-SQL statements
If you need to access whole recordset, rather than row at a time you can use SqlDataAdapter (SqlDataAdapter vs SqlDataReader).

Related

Trying to pass database name and text to call a SQL command in different file

I'm calling the following code:
public static bool checkDuplicateProducts(string item1, string item2)
{
// new connection
SqlConnection con = new SqlConnection(stringCon);
// adapter query
SqlDataAdapter sda = new SqlDataAdapter("SELECT * FROM '" + item1 + "' WHERE ProductCode='" + item2 + "'", con);
DataTable dt = new DataTable();
sda.Fill(dt);
if (dt.Rows.Count >= 1)
{
return true;
}
else
{
return false;
}
}
from this:
string tableName = "Product";
else if(Functions.checkDuplicateProducts(tableName, textBox2.Text) == true)
{
MessageBox.Show("The id is already available", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
I get this error when doing so:
System.Data.SqlClient.SqlException: 'Incorrect syntax near ' Product '.'
Your table shouldn't be single quoted i.e SELECT * FROM table_name
"SELECT * FROM '" + item1 + "'
Should be
"SELECT * FROM " + item1 + "
However, you should really be using parameterised queries in general, lest you be on the wrong end of an sql injection attack
Select * from Table Name you Should by Not Accepted c# for the query in 'Table Name'
REPLACE THE CODE
SqlDataAdapter sda = new SqlDataAdapter("SELECT * FROM " + item1 + " WHERE ProductCode='" + item2 + "'", con);

SQL TOP 1 query when generating random ID with C# application [duplicate]

This question already has answers here:
Execute Insert command and return inserted Id in Sql
(8 answers)
Closed 3 years ago.
I have a C# application which creates an entry in the SQL database to table_customer_invoice and table_customer_invoice_detail, when a user sells a particular item from the application, as soon as the user enters the amount tendered, an insert in the customer_invoice table is done where ID is an identity column which I use that ID by reading the last entered ID by (SELECT TOP 1 ID FROM CUSTOMERINVOICE ORDER BY ID DESC) to insert in the table_customer_invoice_detail.
It works well the only problem is when two users sell an item together at the exact same time from different computers than the (SELECT TOP 1 ID) clashes and both users get the same ID as it looks for the last ID created. Is there any other way I can get the exact ID for the particular user?
This is the code in the application
SqlCommand cmd3 = new SqlCommand("insert into CUSTOMERINVOICE(INVOICEDATE,INVOICESTATUS,ISDEBTORINVOICE,ISLAYBYEINVOICE,INVOICETYPE,INVOICETOTAL,salesrep,dayended)" + "values(GETDATE(),0,0,0,1,'" + Convert.ToDecimal(lblTotalAmount.Text.ToString()) + "','" + txtSalesRep.Text + "',0)", conn);
cmd3.ExecuteNonQuery();
SqlDataAdapter ada2 = new SqlDataAdapter("SELECT TOP 1 ID FROM CUSTOMERINVOICE ORDER BY ID DESC", conn);
DataTable dt2 = new DataTable();
ada2.Fill(dt2);
DataRow dr2 = dt2.Rows[0];
CUSTID = Int32.Parse(dr2["ID"].ToString());
foreach (DataGridViewRow row in dgSaleBasket.Rows)
{
SqlDataAdapter ada5 = new SqlDataAdapter("SELECT itemcode,onhand,costincl FROM stmast where itemcode ='" + row.Cells[1].Value + "'", conn);
DataTable dt5 = new DataTable();
ada5.Fill(dt5);
int quantityPurchased = Int32.Parse(row.Cells[4].Value.ToString());
for (int i = 0; i < dt5.Rows.Count; i++)
{
DataRow dr5 = dt5.Rows[i];
double SellPrice = Convert.ToDouble(row.Cells[5].Value.ToString());
costinc = Convert.ToDouble(dr5["costincl"].ToString());
profit = (SellPrice - costinc) * quantityPurchased;
totalprofit = profit + totalprofit;
SqlCommand cmd4 = new SqlCommand("insert into CUSTOMERINVOICEDETAIL(INVOICEID,ITEMCODE,DESCRIPTION,QUANTITY,PRICE,profit,refund)" + "values(" + CUSTID + ",'" + row.Cells[1].Value.ToString() + "','" + row.Cells[2].Value.ToString() + "'," + row.Cells[4].Value.ToString() + ",'" + Convert.ToDecimal(row.Cells[5].Value.ToString()) + "'," + profit + ",0)", conn);
cmd4.ExecuteNonQuery();
SqlCommand cmd6 = new SqlCommand("UPDATE stmast SET onhand =onhand-" +quantityPurchased + ", lastSold =GETDATE() , lastSoldPrice=" + Convert.ToDecimal(row.Cells[5].Value.ToString()) + ",totalQtySold=totalQtySold+" + quantityPurchased + " WHERE itemcode ='" + row.Cells[1].Value + "'", conn);
cmd6.ExecuteNonQuery();
SqlCommand cmd2 = new SqlCommand("UPDATE customerinvoice set invoiceprofit=" + totalprofit + " WHERE id =" + CUSTID, conn);
cmd2.ExecuteNonQuery();
}
Maybe you can try by using INSERTED temporary table
example :
CREATE DATABASE TEST
USE TEST
CREATE TABLE client
(
id INT IDENTITY(1,1),
name varchar(20)
)
DECLARE #tempTable TABLE(id INT,
[name] varchar(20))
INSERT client(name)
OUTPUT INSERTED.* INTO #tempTable
VALUES ('Marc');
SELECT * FROM #tempTable
-- Return |1|Marc|

Retrieving a row identity

I want to return the row ID from SQL Server through C#. Below is the code I am using:
const string sqlQuery = "SELECT ID " +
"FROM CleaningCycleTime " +
"WHERE ActualFinishDayTime < DATEADD(day, -60, GETDATE()) AND LotWorkOrder = #LotWorkOrder AND Process = #Process AND CleanType = #CleanType " +
"Group By ID " +
"Having (Min(ActualStartDayTime) IS NOT NULL AND Max(ActualFinishDayTime) IS NOT NULL)";
using (SqlCommand myCommand = new SqlCommand(sqlQuery, _myConnection))
{
try
{
myCommand.Parameters.AddWithValue("#LotWorkOrder", lstOpenCleans.SelectedItem.ToString());
myCommand.Parameters.AddWithValue("#Process", lstProcess.SelectedItem.ToString());
myCommand.Parameters.AddWithValue("#CleanType", lstProcess.SelectedItem.ToString());
_myConnection.Open();
SqlDataReader myReader = myCommand.ExecuteReader();
while (myReader.Read())
{
txtID.Text = myReader["ID"].ToString();
}
_myConnection.Close();
}
catch (Exception ee)
{
MessageBox.Show(ee.ToString());
_myConnection.Close();
}
}
Which generates
SELECT ID
FROM CleaningCycleTime
WHERE ActualFinishDayTime < DATEADD(day, -60, GETDATE())
AND LotWorkOrder = 'X90744'
AND Process = 'PRE BLEND'
AND CleanType = 'FULL'
GROUP BY
ID
HAVING
(Min(ActualStartDayTime) IS NOT NULL
AND Max(ActualFinishDayTime) IS NOT NULL)
When I run the generated query in SQL Server Management Studio, it returns a value. When I do this in C#, it gets as far as myReader.Read(), but never loops
I notice a couple of things:
1 - No quotes around your C# string where appropriate.
SQL:
AND LotWorkOrder = 'X90744'
AND Process = 'PRE BLEND'
AND CleanType = 'FULL'
vs
C#:
"AND LotWorkOrder = #LotWorkOrder AND Process = #Process AND CleanType = #CleanType "
2 - We do not see how your connection is defined. Why not wrap it in a using statement?
To be concise:
using (var cn = new SqlConnection("connection string"))
{
cn.Open();
using (var cmd = cn.CreateCommand())
{
// set the command text
const string sqlQuery = "SELECT ID " +
"FROM CleaningCycleTime " +
"WHERE ActualFinishDayTime < DATEADD(day, -60, GETDATE()) AND LotWorkOrder = '#LotWorkOrder' AND Process = '#Process' AND CleanType = '#CleanType' " +
"Group By ID " +
"Having (Min(ActualStartDayTime) IS NOT NULL AND Max(ActualFinishDayTime) IS NOT NULL)";
cmd.CommandText = sqlQuery;
// Add your paramters to the command object.
cmd.Parameters.AddWithValue("#LotWorkOrder", lstOpenCleans.SelectedItem.ToString());
cmd.Parameters.AddWithValue("#Process", lstProcess.SelectedItem.ToString());
cmd.Parameters.AddWithValue("#CleanType", lstProcess.SelectedItem.ToString());
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
txtID.Text = myReader["ID"].ToString();
}
}
}
}
New sqlQuery:
const string sqlQuery = "SELECT ID " +
"FROM CleaningCycleTime " +
"WHERE ActualFinishDayTime < DATEADD(day, -60, GETDATE()) AND LotWorkOrder = '#LotWorkOrder' AND Process = '#Process' AND CleanType = '#CleanType' " +
"Group By ID " +
"Having (Min(ActualStartDayTime) IS NOT NULL AND Max(ActualFinishDayTime) IS NOT NULL)";

Database only updating first row with diffrent value C#

string connetionString = null;
SqlConnection connection;
SqlCommand command;
SqlDataAdapter adpter = new SqlDataAdapter();
DataSet ds = new DataSet();
XmlReader xmlFile;
string sql = null;
int ID = 0;
string Name = null, Text = null, Screenname = null;
connetionString = "myconnection";
connection = new SqlConnection(connetionString);
xmlFile = XmlReader.Create("my.XML", new XmlReaderSettings());
ds.ReadXml(xmlFile);
int i = 0;
connection.Open();
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
ID = Convert.ToInt32(ds.Tables[0].Rows[i].ItemArray[0]);
Text = ds.Tables[0].Rows[i].ItemArray[1].ToString().Replace("'", "''");
Name = ds.Tables[0].Rows[i].ItemArray[2].ToString().Replace("'", "''");
Screenname = ds.Tables[0].Rows[i].ItemArray[3].ToString().Replace("'", "''");
//sql = "insert into nicktest values(" + ID + ",'" + Text + "'," + Name + "," + Screenname + "," + DateTime.Now.ToString() + ")";
sql = "If Exists(Select * from niktest2 Where Id = ID) " +
" BEGIN " +
" update niktest2 set Name = '" + Text + "' , Screenname = '" + Name + "', Profimg= '" + Screenname + "', InsertDateTime= '" + DateTime.Now.ToString() + "' where Id=ID" +
" END " +
" ELSE " +
" BEGIN " +
" insert into niktest2(Id,Name,Screenname,Profimg,InsertDateTime) values('" + ID + "','" + Text + "','" + Name + "','" + Screenname + "' ,'" + DateTime.Now.ToString() + "')" +
" END ";
command = new SqlCommand(sql, connection);
adpter.InsertCommand = command;
adpter.InsertCommand.ExecuteNonQuery();
}
}
after running this code only first row gets updated even my xml file is having more data.
i Want to insert all data into database with assign id to it in xml file.
Please help..
As soon as you have inserted one row, this condition will be true:
If Exists(Select * from niktest2 Where Id = ID)
So you will perform the update, rather than the insert, so you will only ever get one row in the database.
Since you are using SQL Server 2008 I would adopt a completely different approach, using Parameterised queries, MERGE, and table valued parameters.
The first step would be to create your table valued parameter (I have had to guess at your type:
CREATE TYPE dbo.nicktestTableType AS TABLE
(
Id INT,
Name VARCHAR(255),
Screenname VARCHAR(255),
Profimg VARCHAR(255)
);
Then you can write your MERGE statement to upsert to the database:
MERGE nicktest WITH (HOLDLOCK) AS t
USING #NickTestType AS s
ON s.ID = t.ID
WHEN MATCHED THEN
UPDATE
SET Name = s.Name,
Screenname = s.Screenname,
Profimg = s.Profimg,
InsertDateTime = GETDATE()
WHEN NOT MATCHED THEN
INSERT (Id, Name, Screenname, Profimg, InsertDateTime)
VALUES (s.Id, s.Name, s.Screenname, s.Profimg, GETDATE());
Then you can pass your datatable to the query as a parameter:
using (var command = new SqlCommand(sql, connection))
{
var parameter = new SqlParameter("#NickTestType", SqlDbType.Structured);
parameter.Value = ds.Tables[0];
parameter.TypeName = "dbo.nicktestTableType";
command.Parameters.Add(parameter);
command.ExecuteNonQuery();
}
If you don't want to make such a drastic change, then you should at the very least use parameterised queries, so your SQL would be:
IF EXISTS (SELECT 1 FROM nicktest WHERE ID = #ID)
BEGIN
UPDATE nicktest
SET Name = #Name,
ScreenName = #ScreeName,
InsertDateTime = GETDATE()
WHERE ID = #ID;
END
ELSE
BEGIN
INSERT (Id, Name, Screenname, Profimg, InsertDateTime)
VALUES (#ID, #Name, #Screenname, #Profimg, GETDATE());
END
Or preferably still using MERGE as the HOLDLOCK table hint prevents (or at least massively reduces the chance of) a race condition:
MERGE nicktest WITH (HOLDLOCK) AS t
USING (VALUES (#ID, #Name, #ScreenName, #ProfImg)) AS s (ID, Name, ScreenName, ProfImg)
ON s.ID = t.ID
WHEN MATCHED THEN
UPDATE
SET Name = s.Name,
Screenname = s.Screenname,
Profimg = s.Profimg,
InsertDateTime = GETDATE()
WHEN NOT MATCHED THEN
INSERT (Id, Name, Screenname, Profimg, InsertDateTime)
VALUES (s.Id, s.Name, s.Screenname, s.Profimg, GETDATE());
This will be considerably less efficient than the first solution though using table-valued parameter
Then your c# would be something like:
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#ID", ds.Tables[0].Rows[i][0]);
command.Parameters.AddWithValue("#Name", ds.Tables[0].Rows[i][1]);
command.Parameters.AddWithValue("#ScreeName", ds.Tables[0].Rows[i][2]);
command.Parameters.AddWithValue("#ProfImg", ds.Tables[0].Rows[i][3]);
command.ExecuteNonQuery();
}
}

How to write IF SQL statement in C# for retrieving values from database

I have these three columns in UI. In dropdown I have a AllRecords and some other field. I select that AllRecords field and I enter start and end date details.
Now I write a query for that for retrieving the values.
When he select AllRecords, depending upon start and end dates, it have to display OR retrieve the data from database table.
I have written a query if the user will select other values, it looks like this ,
DataTable dt = new DataTable();
string queryStr = "SELECT Day,Date,Name,Task,Hours from TaskManualDetails where Date between '"
+ DateTime.Parse(txtStartDate.Text).ToString("yyyy-MM-dd")
+ "' and '"
+ DateTime.Parse(txtEndDate.Text).ToString("yyyy-MM-dd")
+ "' and Name ='"
+ DropDownList1.Text.ToString()
+ "'";
SqlDataAdapter s1 = new SqlDataAdapter(queryStr, conn);
s1.Fill(dt);
Now the problem is I have to write query for AllRecords.
try this:
DataTable dt = new DataTable();
string queryStr = "SELECT Day,Date,Name,Task,Hours from TaskManualDetails ";
if ( DropDownList1.Text.ToString() != "AllRecords")
queryStr=queryStr+" where Date between '" + DateTime.Parse(txtStartDate.Text).ToString("yyyy-MM-dd") + "' and '" + DateTime.Parse(txtEndDate.Text).ToString("yyyy-MM-dd") + "'"+" and Name ='" + DropDownList1.Text.ToString() + "'";
SqlDataAdapter s1 = new SqlDataAdapter(queryStr, conn);
s1.Fill(dt);
Only a small change in your query
You have to append and Name ='" + DropDownList1.Text.ToString() to the query only if its not AllRecords
Be care about SQL Injection. Use SQLParameter like this:
DataTable dt = new DataTable();
SqlDataAdapter s1 = new SqlDataAdapter();
s1.SelectCommand.Connection = conn;
string queryStr = "SELECT Day,Date,Name,Task,Hours from TaskManualDetails WHERE Date BETWEEN #StartDate AND #EndDate";
s1.SelectCommand.Parameters.AddWithValue("StartDate", DateTime.Parse(txtStartDate.Text).ToString("yyyy-MM-dd"));
s1.SelectCommand.Parameters.AddWithValue("EndDate", DateTime.Parse(txtEndDate.Text).ToString("yyyy-MM-dd"));
if (DropDownList1.Text.ToString() != "AllRecords")
{
queryStr = queryStr + " AND Name = #Name";
s1.SelectCommand.Parameters.AddWithValue("Name", DropDownList1.Text.ToString());
}
s1.SelectCommand.CommandText = queryStr;
s1.Fill(dt);

Categories