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'";
Related
i need your help again!
my query looks like this
Select * from USERS Where username = 'username1';
now i want to add some OR to the where clause:
Select * from USERS Where username = 'username1' OR username = 'username2';
the problem is must generate the query dynamical, because the selected user count is from 1 to 10;
i created a function that adds all user to a string
output:
'username = 'username1' OR username = 'username2''
i declare #names
and now my query looks like this:
DECLARE #names varchar(1000) = 'username = 'username1' OR username = 'username2''
Select * from USERS Where #names;
what is the right way to some OR's in the where clause?
thank you
Use IN()
SELECT *
FROM
USERS
WHERE
username IN('username1','username2')
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
)"
Lets say i have two tables with almost the same structure
TableFrom
ID bigint
Username nvarchar
Password nvarchar
Name nvarchar
TableTo
ID bigint
Username nvarchar
Password nvarchar
Now i want to generate an Insert into SQL query ( using parameters ) but only for those fields who are the same in both tables. ( id, username, password )
I thought about reading those two table structure queries into dataTable and after that loop with LINQ to get array of fields which are the same in bot tables ?
Dim dtFrom as new datatable
dim dtTo as NEW dataTable
dtTo = _LoadAvaliableToFields()
dtFrom = _loadAvailableFromFields()
How would that LINQ go ?
After that i need to add the Insert query to database using parameters. Is there any simpler way to do this ?
Using query syntax the "select" query would be very similar to a SQL query:
Dim query =
From idFrom In TableFrom _
Join idTo In TableTo _
On New With {Key .ID = idFrom.ID, Key .U = idFrom.Username, Key .P = idFrom.Password} _
Equals New With {Key .ID = idTo.ID, Key .U = idTo.Username, Key .P = idTo.Password} _
Select idFrom
To do an insert you'd need to add objects to the appropriate collections in the context, then call SaveChanges.
I would note that a direct SQL query would be more efficient:
INSERT INTO {destination}
SELECT f.ID,f.Username,f.Password
FROM TableFrom f
INNER JOIN TableTo t
ON f.ID = t.ID AND f.Username = t.Username AND f.Password = t.Password
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 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'