I have 3 Tables. Item, StockDetail, Branch
I want to INSERT 2 of them at once. The Item and StockDetail table.
Item has 3 columns = ItemID, Title, Price.
StockDetail has 3 columns = ItemID, BranchID, Stock.
Branch has 1 column = BranchID.
In this code below, INSERT into Item works fine, but not for StockDetail table, it doesn't INSERT anything!
Now for the StockDetail if it works, I want to insert it with the condition below:
If you add an item, then it'll add this item with all existed BranchID.
That mean, every Branches will have this item.
e.g:
You add an item, while
Branch has 3 rows of BranchID = BR000, BR001, BR002.
It will insert to StockDetail with 3 rows as well, at once (single Query)
Complete result of StockDetail (single Query):
ItemID | BranchID | Stock
______________________________
IM000 | BR000 | 0
IM000 | BR001 | 0
IM000 | BR002 | 0
The Code:
'Add function'
'Insert to StockDetail'
Dim theCommand As New SqlCommand
Dim theDataAdapter As New SqlDataAdapter
Dim theDataTable As New DataTable
theCommand.Connection = theConnection
theCommand.CommandText = "INSERT INTO StockDetail VALUES(
'" & Me.TextBox_ItemID.Text & "',
SELECT COUNT(BranchID) FROM Branch,
'0'
)"
theDataAdapter.SelectCommand = theCommand
'Insert to Item'
theCommand.Connection = theConnection
theCommand.CommandText = "INSERT INTO Item VALUES('" & Me.TextBox_ItemID.Text & "', '" & Me.TextBox_Title.Text & "', '" & Me.TextBox_Price.Text & "')"
theDataAdapter.SelectCommand = theCommand
theDataAdapter.Fill(theDataTable)
DataGridView_Item.DataSource = theDataTable
theCommand.Dispose()
theDataAdapter.Dispose()
UPDATE:
The code below will tell you the working multiple INSERT, but not with the BranchID INSERT.
'Insert to StockDetail'
theConnection.Open()
Dim theCommand As New SqlCommand
Dim theDataAdapter As New SqlDataAdapter
theCommand.Connection = theConnection
theCommand.Parameters.Add("#ItemID", SqlDbType.VarChar).Value = Me.TextBox_ItemID.Text
theCommand.CommandText = "INSERT INTO StockDetail(ItemID, BranchID, Stock) SELECT #ItemID, COUNT(Branch.BranchID), '0' FROM Branch GROUP BY Branch.BranchID"
theDataAdapter.SelectCommand = theCommand
Using theDataAdapter
theCommand.ExecuteNonQuery()
theCommand.Parameters.Clear()
theCommand.Dispose()
theConnection.Close()
SqlConnection.ClearPool(theConnection)
End Using
What do I want now?
Well instead of inserting 1, 1, . . .
I'd like to INSERT it with BR000, BR001 . . . (Based on all existed BranchID)
Here is how you use a parameter in your first insert statement. I think you still have some very serious logic issues here though. This is going to insert 1 row into StockDetail and the values don't make any sense at all. You would be inserting the count of rows from the Branch table as the BranchID which is probably not what you really want. I suspect what you want is a row in this table for each Branch?
theCommand.CommandText = "INSERT INTO StockDetail(ItemID, BranchID, Price) VALUES(
#ItemID,
(SELECT COUNT(BranchID) FROM Branch),
0
)"
theCommand.Parameters.Add("#ItemID", SqlDbType.Varchar).Value = Me.TextBox_ItemID.Text;
I suspect what you really want is something more like this.
theCommand.CommandText = "INSERT INTO StockDetail(ItemID, BranchID, Price)
select #ItemID
, BranchID
, 0
from Branch";
theCommand.Parameter.Add("#ItemID", SqlDbType.Varchar).Value = Me.TextBox_ItemID.Text;
The SQL command text for the insert into StockDetail doesn't do what you say you want to happen. This code, though syntactically incorrect (if you want to use a SELECT as a value, you need to surround it in parentheses like this:
theCommand.CommandText = "INSERT INTO StockDetail VALUES(
'" & Me.TextBox_ItemID.Text & "',
(SELECT COUNT(BranchID) FROM Branch),
'0'
)"
), would insert your ID, a count of the number of branches you have, and a zero into the table.
For what you say you want to have happen, your code would look more like this:
theCommand.CommandText = "INSERT INTO StockDetail SELECT
'" & Me.TextBox_ItemID.Text & "',
BranchID, '0' FROM Branch
)"
Related
Using VB.NET and SQL Server: I have a table [Item_List]. When I add a new item from a Windows form, I want to insert the record into the Item_List table, get the ItemID which is an IDENTITY, and use that to insert a corresponding record into the financial tracking [Inventory_Transactions] table.
I tested the following query directly in a T-SQL query window with success:
DECLARE #OutputTbl TABLE (ItemID INT);
INSERT INTO [Item_List] (Item_Name, Vendor, Quantity, Price, Category, Active, Notes, Created)
OUTPUT INSERTED.ItemID INTO #OutputTbl(ItemID)
VALUES ('Test Item', 'Walmart', 42, 4.22, 'Stuff', 1, '', CURRENT_TIMESTAMP);
INSERT INTO Inventory_Transactions (TransDate, Category, Transactee, Amount, Item, Quantity, Description)
SELECT
CURRENT_TIMESTAMP, 'Stuff', 'Walmart', -4.22, ItemID, 42, '';
However when I try to run using ExecuteNonQuery() I get an error
Invalid column name 'ItemID'
I've used the exact script from above and also below with parameters - same error.
Dim sql As String = "DECLARE #OutputTbl TABLE (ItemID INT); " &
"INSERT INTO [Item_List] (Item_Name, Vendor, Quantity, Price, Category, Active, Notes, Created) " &
"OUTPUT INSERTED.ItemID INTO #OutputTbl(ItemID) " &
"VALUES (#ItemName, #Vendor, #Quantity, #Price, #Category, #Active, #Notes, CURRENT_TIMESTAMP); " &
"INSERT INTO Inventory_Transactions (TransDate, Category, Transactee, Amount, Item, Quantity, Description) " &
"SELECT CURRENT_TIMESTAMP, #Category, #Vendor, '-' + #Price, ItemID, #Quantity, #Notes;"
Using conn As New SqlConnection(My.Settings.dbConnectionString)
Dim cmd As New SqlCommand(sql, conn)
If Not IsNothing(params) Then
For Each param In params
cmd.Parameters.Add(param)
Next
End If
If cmd.Connection.State <> ConnectionState.Open Then
cmd.Connection.Open()
Dim rows As Integer = cmd.ExecuteNonQuery()
End Using
How can I implement this in VB?
I just tested this code and it worked exactly as expected:
Dim sql = "INSERT INTO Parent (ParentName) VALUES (#ParentName);
INSERT INTO Child (ChildName, ParentId) VALUES (#ChildName, SCOPE_IDENTITY())"
command.CommandText = sql
command.Parameters.Add("#ParentName", SqlDbType.NVarChar, 50).Value = "Parent1"
command.Parameters.Add("#ChildName", SqlDbType.NVarChar, 50).Value = "Child1"
command.ExecuteNonQuery()
The SCOPE_IDENTITY function gets the last identity value generated in the current scope.
If you need to use the identity value multiple times then you can assign it to a parameter and use that, e.g.
Dim sql = "INSERT INTO Parent (ParentName) VALUES (#ParentName);
SELECT #ParentId = SCOPE_IDENTITY();
INSERT INTO Child (ChildName, ParentId) VALUES (#ChildName, #ParentId)"
command.CommandText = sql
command.Parameters.Add("#ParentName", SqlDbType.NVarChar, 50).Value = "Parent1"
command.Parameters.Add("#ParentId", SqlDbType.Int).Direction = ParameterDirection.Output
command.Parameters.Add("#ChildName", SqlDbType.NVarChar, 50).Value = "Child1"
command.ExecuteNonQuery()
If you need to use the identity value in your VB code then also use a parameter like this:
Dim parentSql = "INSERT INTO Parent (ParentName) VALUES (#ParentName);
SELECT #ParentId = SCOPE_IDENTITY();"
parentCommand.CommandText = parentSql
parentCommand.Parameters.Add("#ParentName", SqlDbType.NVarChar, 50).Value = "Parent1"
parentCommand.Parameters.Add("#ParentId", SqlDbType.Int).Direction = ParameterDirection.Output
parentCommand.ExecuteNonQuery()
Dim childSql = "INSERT INTO Child (ChildName, ParentId) VALUES (#ChildName, #ParentId)"
childCommand.CommandText = childSql
childCommand.Parameters.Add("#ChildName", SqlDbType.NVarChar, 50).Value = "Child1"
childCommand.Parameters.Add("#ParentId", SqlDbType.Int).Value = parentCommand.Parameters("#ParentId").Value
childCommand.ExecuteNonQuery()
I think this:
"SELECT CURRENT_TIMESTAMP, #Category, #Vendor, '-' + #Price, ItemID, #Quantity, #Notes;"
should be:
"SELECT CURRENT_TIMESTAMP, #Category, #Vendor, '-' + #Price, ItemID, #Quantity, #Notes from #OutputTbl;"
if i click the search button, i keep on receiving an error at the value of IDNo, incorrect syntax near '11111' can someone help me?
With acc
IDNo = .IDNo
StartDate = DateTime.Parse(.StartDate).ToString("M/d/yyyy")
EndDate = DateTime.Parse(.EndDate).ToString("M/d/yyyy")
ProjectName = .ProjectName
ReferenceNo = .ReferenceNo
TaskCode = .TaskCode
FileName = .Filename
End With
dgAccomplishment.DataSource = Nothing
dgAccomplishmentPT.DataSource = Nothing
da = New SqlDataAdapter("dbo.process_time #User='" & IDNo & "' ,#From='" & StartDate & "',#To='" & EndDate & " 11:59:59 PM'", DB.GetConnection)
dt = New DataTable
da.Fill(dt)
dgAccomplishment.DataSource = dt
dgAccomplishment.Columns("ID").Visible = False
dgAccomplishment.Columns("TimeSave").Visible = False
da.Dispose()
dt.Dispose()
this is my stored procedure
SELECT a.ID, RTRIM(a.Last_User) [ID No.],
RTRIM(Users.FIRSTNAME + ' ' + Users.INITIAL + '. ' + Users.LASTNAME) [Name],
RTRIM(a.ProjectName) [Project Name],
a.ProjectNo, a.ProjectCode,
RTRIM(a.Filename) [Filename],
RTRIM(a.Filesize) [Filesize],
RTRIM(a.filesizeunit) [FileSizeUnit],
a.TimeSave [TimeSave]
from DBase.dbo.Acc a
INNER JOIN dbo.Users ON a.Last_User = Users.IDNo
WHERE a.Last_User in (#user)
and CONVERT(VARCHAR(10),timesave,101) BETWEEN #From AND #To
ORDER BY RTRIM(a.SubGroup), RTRIM(a.Last_User)
but when i try to run the procedure in a query it works well.
Because you are using string concatenation, you have the age old single quote problem: If IDNo value contains a single quote, then your query will fail.
What's worse, your code is susceptible to sql injection attacks.
You have to escape ALL parameters for single quotes, replacing them by 2 single quotes.
Best solution here: use parametrized sql
I am struggling to generate a 'notifications' query to work correctly at the moment.
I'm working on a query that will add a string to a table in which will add multiple rows at once, with only one column of which will be changed in this 'bulk insert':
I currently have:
public static void addNotification(string notification)
{
SqlConnection scon = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]);
using (SqlCommand scmd = new SqlCommand())
{
scmd.Connection = scon;
scmd.CommandType = CommandType.Text;
scmd.CommandText = "INSERT INTO notificationAck (Email, Notification, isAcknowledged) VALUES ((SELECT Email FROM AspNetUsers), '" + notification + "' ,0)";
scon.Open();
int status = scmd.ExecuteNonQuery();
scon.Close();
}
}
However, on passing this a string like: "this is a notification", it comes up with the following error:
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression. The statement has been terminated.
So, could someone possibly explain how this query should be run?
The table has the columns:
I understand the 'PK1' isn't the best of practises, but this is only a table for testing purposes (it's set to auto increment)
So, the isAcknowledged should be set to 0, the notification should be this string, and the email should be selected from each row of the table AspNetUsers?
Would anyone e able to explain to me how I should go about adding this data into my db?
Something like this should work:
scmd.CommandText = "INSERT INTO notificationAck (Email,
Notification,
isAcknowledged)
SELECT Email, '" + notification + "', 0
FROM AspNetUsers";
INSERT INTO SELECT does not require VALUES. Hence, you only have to use a SELECT statement that retrieves Email field from AspNetUsers plus two constant values.
You don't want to use VALUES when using a query to generate your results. You can change the INSERT query to this:
INSERT INTO notificationAck (Email, Notification, isAcknowledged)
SELECT Email, 'SOME STRING', 0 FROM AspNetUsers
Which translated in to your code would look like:
scmd.CommandText = "INSERT INTO notificationAck (Email, Notification, isAcknowledged)
SELECT Email, '" + notification + "', 0 FROM AspNetUsers";
Select Top 1 in Sub Query if you want to insert only 1 row
try
INSERT INTO notificationAck (Email, Notification, isAcknowledged)
VALUES ((SELECT top 1 Email FROM AspNetUsers), '" + notification + "' ,0)
if you want to insert all rows from AspNetUsers then use
INSERT INTO notificationAck(Email,Notification, isAcknowledged) select
Email,''+notification +"',1 from AspNetUsers
Your query
SELECT Email FROM AspNetUsers
returns more than one row as your error says. You need to change it so that it returns only one row, for example:
SELECT TOP 1 Email FROM AspNetUsers
Then change your command as below
scmd.CommandText = "INSERT INTO notificationAck (Email, Notification, isAcknowledged) SELECT TOP 1 Email " + notification + "' ,0 FROM AspNetUsers'";
if you want to insert more than one row, the remove top 1 from query.
scmd.CommandText = "INSERT INTO notificationAck (Email, Notification, isAcknowledged) SELECT Email " + notification + "' ,0 FROM AspNetUsers'";
i try to insert data table to two table from a windowform , so i found this code :
INSERT INTO patient (id, name, sex), checkIn (chID, Date, illness) VALUES ('" & txt1.text & "', '" & txt2.text & "','" & txt3.text & "','" & txt4.text & "', '" & txt5.text & "', '" & txt6.text & "')
is it correct ?
You can not insert data into 2 tables simultaneously. Split the insert statements into 2 statements
INSERT INTO patient(id, name, sex) VALUES (value1, value2, value3)
INSERT INTO checkIn(chID, Date, illness) VALUES (value4, value5, value6)
The only way to insert data in two tables using a single SQL statement is using OUTPUT clause which returns information from each row affected by an INSERT, UPDATE, DELETE, or MERGE statement.
INSERT INTO [table1] ([data])
OUTPUT [inserted].[id], [external_table].[col2]
INTO [table2] SELECT [col1]
FROM [external_table]
it's return the error like below
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near tablename
you have to write both statement seperate.
insert into tablename1(col1,col2,col3) value (val1,val2,val3)
insert into tablename2(col4,col5,col63 value (val4,val5,val6)
I have a query that I have to run that requires me to get rows from a table based on the value of a field in another table (which I have gotten earlier).
I currently have it done like this (simplified).
cmd.commandtext = "SELECT * FROM TableB WHERE FieldC = '" & TableA.FieldF & "'"
cmdReader = cmd.executereader()
If cmdReader.HasRows Then
Do something
Else
cmdReader.close()
cmd.commandtext = "SELECT * FROM TableB WHERE FieldC = 'Generic'"
cmdReader = cmd.executereader()
If cmdReader.HasRows Then
Do something
Else
Do something
End If
End If
Is there a way that I can combine those two queries so that I get one or the other?
Let me know if you need any more info, not sure I've explained this properly.
Try:
WHERE FieldC = '" & TableA.FieldF & "' OR FieldC = 'Generic'
Or
WHERE FieldC IN ('" & TableA.FieldF & "', 'Generic')
Even better, use parameters:
WHERE FieldC IN (#FieldF, 'Generic')
...
cmd.Parameters.Add("#FieldF", TableA.FieldF);
EDIT: To select only one set of rows in one query, you could:
SELECT *
FROM TableB
WHERE FieldC = #FieldF
UNION ALL
SELECT *
FROM TableB
WHERE NOT EXISTS (SELECT * FROM TableB WHERE FieldC = #FieldF)
AND FieldC = 'Generic'