SELECT inside INSERT query? - c#

I am trying to insert the user id from table users inside table session , field session_user, using textbox , but it seems it doesn't work ..
Here is my SQL code, I am using visual studio and trying to insert to a SQL Server table
SqlCommand addsession = new SqlCommand
("insert into dbo.session(session_user)
values (select user_id from dbo.users where username = '" + TextBox1.Text + "')",
badersql);

You shouldn't use the VALUES keyword when you're doing an INSERT ... SELECT:
insert into dbo.session (session_user) select user_id from dbo.users ...

If you are inserting the result of a query into another table, just leave out the VALUES keyword.
The VALUES keyword can always be replaced by a simple SELECT 'dummy', 'value' of the values you want to insert, but I suggest you still use VALUES whenever you want to make it clear that your results do not come from a query.
That being said, please use parameterized queries!! Imagine if someone were to enter the following text into TextBox1:
' or 1 = 1
What would happen?

To insert records from a query use this insert syntax:
insert into dbo.session (session_user)
select user_id from dbo.users where username = '" + TextBox1.Text + "'
You may want to do a select top 1 userid if you are expecting one row to be inserted like in the values statement.

i did it , the problem was that i can not name my record session_user , so i replaced with se_user and that solve the problem .
thank u all for ur help
so the correct sql statement is
insert into sessions (se_user) select USER_ID from users where username = '';

Related

insert code error

insert into customer (Advance,status)
values(#Advance,#status)
where Name='" + txtcname.Text.Trim() + "'";
in the above insert statement in going to insert 2 values based in condition but i'm getting error in where condition...
incorrect syntax near keyword where
this is the error
Insert query do not needs Where clause. Just write
insert into customer (Advance, status) values(#Advance, #status)
Are you trying to insert or update? if you need to update an existing record then use update instead of insert like this:
update customer set Advance=#Advance, status=#status
where Name='" + txtcname.Text.Trim() + "'";
EDIT
Aforementioned update query will serve the purpose but its recommended to use stored procedures/parameterized queries for SQL injection safety. You should following use approach:
Private void UpdateRecord(string advance,string status, string name)
{
//SqlConnection con
SqlCommand cmdUpdate = new SqlCommand("update customer set Advance = #Advance, status = #Status where Name=#Name", con);
cmdUpdate.Parameters.AddWithValue("#Advance", advance);
cmdUpdate.Parameters.AddWithValue("#Status", status);
cmdUpdate.Parameters.AddWithValue("#name", name);
cmdUpdate.ExecuteNonQuery();
}
Pass your data as following:
UpdateRecord(#Advance,#Status,txtcname.Text.Trim());
You can't use 'where' in an insert-statement.
To achieve the same result, you can insert all entries and delete the wrong.
You can use a select-statement after an insert, where you select entries from a table into another. This could be a solution for you, too.
Insert into customer (advance, status) values (...)
select advance, status
from anotherCustomerTable
where ...
P.S. try to prepare the where-part, too.
You can not add where clause with values. You can achieve this with following way
if you really want to insert new rows else you can follow the #Munawar solution
insert into customer (Advance, status)
SELECT #Advance,#status
FROM customer where Name='" + txtcname.Text.Trim() + "'"

C# & SQL Server : how would I add validation to stop duplicate usernames being inserted

I have a form in my windows form application that is for admin users so that they can add, edit and delete users. The problem I have is that admin can insert a new user which has the same username as another user which results in both users having duplicate usernames when logging into the system.
I just need some basic validation so that the username won't be inserted if its a duplicate but I'm not sure how I can add it to the dataadapter.
SqlConnection con = new SqlConnection(#"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|Data.mdf;Integrated Security=True");
con.Open();
SqlDataAdapter sda = new SqlDataAdapter("INSERT INTO Login (FirstName, Role, Username, Password, Surname) VALUES ('" + txtfirstname2.Text + "','" + rolecombo.Text + "','" + txtusername2.Text + "','" + txtpassword2.Text + "','" + txtsurname.Text + "')", con);
sda.SelectCommand.ExecuteNonQuery();
con.Close();
MessageBox.Show("SAVED SUCCESSFULLY !!!!!");
Create an insert trigger or a unique key index:
Trigger to prevent Insertion for duplicate data of two columns
Something like this:
CREATE TRIGGER MyTrigger ON dbo.MyTable
AFTER INSERT
AS
if exists ( select * from table t
inner join inserted i on i.name=t.name and i.date=t.date)
begin
rollback
RAISERROR ('Duplicate Data', 16, 1);
end
go
That's just for insert, you might want to consider updates too.
Update
A simpler way would be to just create a unique constraint on the table, this will also enforce it for updates too and remove the need for a trigger. Just do:
ALTER TABLE [dbo].[TableName]
ADD CONSTRAINT [UQ_ID_Name_Date] UNIQUE NONCLUSTERED
(
[Name], [Date]
)
and then you'll be in business.
Add a WHERE NOT EXISTS clause to your INSERT query to check if the username exists, then use the return value of ExecuteNonQuery (number of rows affected) to figure out if your user was inserted. 0 => not inserted because there was a duplicate.

Copy a database table to another database table with a different structure

I am aware this was asked here. However it doesn't answer my question. I have 10 tables in a database called "merged". I am taking a bunch of other databases with an identical structure as "merged" except that "merged" has an extra column that is a combination of two columns in the table. I am trying to transfer all this data into merged but I believe the extra column I believe is preventing the transfer.
SqlCommand MergeDB = connDestination.CreateCommand();
string sqlMergeDB = "";
int a= 0;
for (a=0; a < tablenames.Length; a++){
string sqlMergeDB = "INSERT INTO sql_merged.dbo." + tablenames[a] + " SELECT * FROM sourceForMerged.dbo." + tablenames[a];
using (SqlDataReader reader = MergeDB.ExecuteReader()) {
while(reader.Read())
{
MessageBox.Show("Transfered a table");
}
}
}
The error occurs at the SqlDataReader row of the code above, which I believe means there is something wrong with the sql command. Please help. Thanks
If you name all the columns in both parts of the INSERT . . . SELECT statement you can map which source column gets inserted into which destination column.
If you imagine TargetTable (Name, ProductType, Date) and SourceTable (Date, Type, Name) then using:
INSERT INTO TargetTable (Name, ProductType, Date)
SELECT Name, Type, Date FROM SourceTable
would move the three columns into the appropriate columns even though the order doesn't match.
If you have "extra" columns in one table or the other you can either leave them out or provide expressions to fill them in:
INSERT INTO TargetTable (Name, ProductType, Date, CombinedValues)
SELECT Name, Type, Date, (ValCol1 + ' ' + ValCol2) FROM SourceTable
has four columns receiving data from four expressions, one of which concatenates two columns worth of data. (In real life, you may find that the concatenation expression is more complicated, but this is the basic idea).
You cannot use a:
Insert Into [Table] Select * From [Table2]
unless the tables schemas are identical. You would have to list out the columns for the Insert Statement.
If possible you could drop the column on the destination table and then add it back after the insert.
You could do something like this to build up you insert code if the table is very wide:
SELECT
'cmd.Parameter.Add("#' + column_name + '", SqlDbType.' + data_type + ');',
column_name 'Column Name',
data_type 'Data Type'
FROM information_schema.columns
WHERE table_name = 'TableName'

Copying row from 1 table to another in SQL

When a user deletes a row in the database, I want to archive it into a separate table in the database rather than delete it or flag it in the current table. I figure I would need to do something like in this link:
How to copy a row from one SQL Server table to another
The thing is, the archive table has 1 extra column in it that does not match the original table (ArchiveTimeStamp). This ArchiveTimeStamp does not exist in the original table, instead I would use something like
archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now);
This is what I have so far:
SqlCommand archiveComm = new SqlCommand("INSERT INTO Archive_Table SELECT * FROM Table WHERE RowID = #rowID", conn);
Is there a way for me to modify the SqlCommand to add another param that doesn't exist in the original Table?
Why not just handle this on the back end? You can create a trigger on the original table to insert into another table after every delete?
Your trigger will look like this:
CREATE TRIGGER onOriginalTableDelete
ON originalTable
FOR DELETE
AS
INSERT INTO anotherTable
SELECT * FROM deleted;
When a record is deleted on the original table, it will insert the deleted record into the other table. You might want to read on using the deleted table here.
Check this SQL Fiddle. Since you're inserting the timestamp in another column, you can just add this on the INSERT INTO SELECT statement:
INSERT INTO OtherTable
SELECT *, CURRENT_TIMESTAMP FROM MainTable;
This could be the query for your trigger:
CREATE TRIGGER onOriginalTableDelete
ON originalTable
FOR DELETE
AS
INSERT INTO anotherTable
SELECT *, CURRENT_TIMESTAMP FROM deleted;
Good question. I'd suggest (as Gian has also suggested) moving the logic you require to backup the deleted row into a trigger that gets fired on delete.
Triggers are events in a database associated to a table which get fired upon an action occurring i.e. insert / update / delete.
So in your scenario, if you create an ON DELETE trigger in the source table, it will get fired when a delete occurs. The SQL contained within the trigger can specify what to do with the deleted data, which in your scenario will be: insert the deleted info into the archive table with a timestamp.
So if you have:
Source_Table:
Col_1
Col_2
Col_3
Archive_Table:
Col_1
Col_2
Col_3
Time_Stamp
You'll need to create a FOR DELETE trigger against Source_Table (something like this):
CREATE TRIGGER SourceDeletedTrigger
ON database.dbo.Source_Table
FOR DELETE
AS
INSERT INTO Archive_Table(Col_1, Col_2, Col_3, Time_Stamp)
SELECT
DELETED.Col_1,
DELETED.Col_2,
DELETED.Col_3,
GETDATE()
FROM DELETED
GO
The above is some rough SQL which may contain a couple of syntax errors but the guts of the idea is conveyed.
You will have to use to explicit column list and values form of the INSERT statement:
INSERT INTO Archive_Table (
Col1
,Col2
,Col3 )
SELECT
Col1
,Col2
,Col3
FROM
Table
WHERE
Row_ID = #Row_ID
See Insert into ... values ( SELECT ... FROM ... )
I think you have to specify the columns with something like this
INSERT INTO tab1
(col1, col2)
SELECT col1, col2
FROM tab2
WHERE RowID = #rowID"
You need to specify the columns name in that case:
archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now);
string SQL = "INSERT INTO Archive_Table (Col1,Col2,ArchiveTimeStamp) " & _
"SELECT Col1,Col2,#ArchiveTimeStamp FROM Table WHERE RowID = #rowID"
SqlCommand archiveComm = new SqlCommand(SQL, conn);
Here is my suggestion, you are forced to supply the column names or it won't let you run the query, however I understand you would prefer a generic solution that worked for any table so I suggest building the insert SQL dynamically, cache it on your application, and then just execute it with your extra archive column. Here is a c# example:
public class ArchiveTableRow
{
private static readonly IDictionary<string, string> _cachedInsertStatements = new Dictionary<string, string>();
public void Archive(string tableName, string rowId)
{
if (_cachedInsertStatements.ContainsKey(tableName) == false)
{
BuildInsertStatement(tableName);
}
var insertQuery = _cachedInsertStatements[tableName];
// ...
SqlCommand archiveComm = new SqlCommand(insertQuery, conn);
// ...
archiveComm.Parameters.AddWithValue("ArchiveTimeStamp", Date.Time.Now);
// ...
}
private void BuildInsertStatement(string tableName)
{
// Get the columns names:
var getColumnNamesQuery = #"
SELECT Table_Schema, Column_Name
FROM Information_Schema.Columns
WHERE Table_Name = '" + tableName + "'
Order By Ordinal_Position";
// Execute the query
SqlCommand archiveComm = new SqlCommand(getColumnNamesQuery, conn);
// Loop and build query and add your archive in the end
// Add to dictionary
}
}
You would use it with something like:
var archiveRow = new ArchiveTableRow();
archiveRow.Archive("TableName", rowId);

I have inserted a row, I want to get it's ID and plus it with an int and insert in that row

I have inserted a row into my table, and I want to get it's ID and plus it with an int and inserted in that row.
But I don't know how to get it's ID.
Here is the insert code:
objCommand.Connection = objConnection;
objCommand.CommandText = "INSERT INTO Moin " +
" (Title, TotalID, Code ) " +
"VALUES (#Title , #TotalID, #Code )";
objCommand.Connection = objConnection;
objCommand.CommandText = "INSERT INTO Moin " +
" (Title, TotalID, Code ) " +
"VALUES (#Title , #TotalID, #Code ) SELECT SCOPE_IDENTITY()";
object id = objCommand.ExecuteScalar();
Try using the OUTPUT clause of SQL Server in your query - it can return any of the just inserted value (here I'm assuming your column is called ID - adapt as needed):
objCommand.Connection = objConnection;
objCommand.CommandText = "INSERT INTO Moin(Title, TotalID, Code ) " +
"OUTPUT Inserted.ID " +
"VALUES (#Title , #TotalID, #Code ); "
and then execute it like this:
int result = (int)objCommand.ExecuteScalar();
Since you're returning just one row and one column (just the INT), you can use .ExecuteScalar() to retrieve that value back from the INSERT statement.
With the OUTPUT clause, you can return any values just inserted - not just the identity column. So you could also return values that are filled by the database with default values, or whatever you need. If you return multiple values, you need to use a data reader to read them all - ExecuteScalar() only works for a single value.
But, as Anders correctly mentioned - using an ORM like Entity Framework would do all of this automatically for you and you wouldn't have to deal with those raw SQL commands anymore....
Building SQL commands in strings should be considered a legacy technique. If you use Entity Framework or linq-to-sql the retrieval of the id is handled automatically for you.
With pure SQL, use the SCOPE_IDENTITY() function to retrieve the id of the inserted element.

Categories