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'
Related
In VB.NET am trying to return all databases that have a specific table. The code I have been using polls just the databases and that works fine. When I add the CASE statement below to get just the ones with the table I need then it returns nothing.
strQuery = "SELECT [name] FROM sys.databases where create_date > '2016-07-01' and [name] not like '_Config_Options' order by create_date desc"
sqlCon = New SqlConnection(strConn)
Using (sqlCon)
Dim sqlComm As SqlCommand = New SqlCommand(strQuery, sqlCon)
sqlCon.Open()
Dim sqlReader As SqlDataReader = sqlComm.ExecuteReader
If sqlReader.HasRows Then
While (sqlReader.Read())
cmbDatabase.Items.Add(sqlReader.GetString(0))
End While
End If
sqlReader.Close()
End Using
The above code returns the full list of databases.
When I change the strQuery to
strQuery = "SELECT [name] FROM sys.databases WHERE CASE WHEN state_desc = ''ONLINE'' THEN OBJECT_ID(QUOTENAME([name]) + ''.[dbo].[MyTable]'', ''U'') END IS NOT NULL order by create_date desc"
I get nothing back. After executing Dim sqlReader As SqlDataReader = sqlComm.ExecuteReader, the code jumps to the End Using. I don't see an error code.
Joel Coehoom gets the credit for answering. I removed the double single quotes and it works.
strQuery = "SELECT [name] FROM sys.databases WHERE CASE WHEN state_desc = 'ONLINE' THEN OBJECT_ID(QUOTENAME([name]) + '.[dbo].[MyTable]', 'U') END IS NOT NULL order by create_date desc"
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
)"
I am trying to get a form setup to launch various reports based on different criteria and I am having problems getting one of the reports that is a GroupBy/Count/Sum based SQL Data source to work between 2 unbound textboxes serving as a FromDate and a ToDate.
VBA script - calling report from form (frmRptFeedback):
Private Sub cmdPrint_Click()
If Not chkPrintPreview Then
Set Application.Printer = Application.Printers.Item(cboPrinter.Value)
End If
Dim strCondition As String
Dim strFromDate As String
Dim strToDate As String
strFromDate = txtFromDate.Value
strToDate = txtToDate.Value
Select Case opgOptions
Case 1 ' Feedback By Employee
If IsNull(cboEmployee.Value) Then
strCondition = "DateSubmitted BETWEEN '" & strFromDate & "' AND '" & strToDate & "'"
Else
strCondition = "RespEmp = '" & cboEmployee.Value & "' AND DateSubmitted BETWEEN '" & _
strFromDate & "' AND '" & strToDate & "'"
End If
Call OpenReport("rptFeedbackByEmp", IIf(chkPrintPreview, acViewPreview, acViewNormal), strCondition)
Case 2 ' Feedback By Team
If IsNull(cboTeam.Value) Then
strCondition = "DateSubmitted BETWEEN '" & strFromDate & "' AND '" & strToDate & "'"
Else
strCondition = "EmpType = '" & cboTeam.Value & "' AND DateSubmitted BETWEEN '" & _
strFromDate & "' AND '" & strToDate & "'"
End If
Call OpenReport("rptFeedbackByTeam", IIf(chkPrintPreview, acViewPreview, acViewNormal), strCondition)
Case 3 ' Feedback By Project #
If IsNull(txtProjectID) Then
strCondition = "DateSubmitted BETWEEN '" & strFromDate & "' AND '" & strToDate & "'"
Else
strCondition = "ProjectID = " & txtProjectID & "AND DateSubmitted BETWEEN '" & _
strFromDate & "' AND '" & strToDate & "'"
End If
Call OpenReport("rptFeedbackByProject", IIf(chkPrintPreview, acViewPreview, acViewNormal), strCondition)
End Select
If Not chkPreview Then
Set Application.Printer = Nothing
End If
End Sub
SQL query - initially pulling data into main SQL View (vueRptFeedback):
SELECT f.FeedbackID, f.BFID, bf.ProjectID, p.ProjectName, e2.Name AS PM, e1.Name AS RespEmp,
et.Description AS EmpType, f.SubByInits, f.DateSubmitted, f.QtyIssues,
f.EstHoursImpact, f.PlusDelta, f.Notes, f.HowResolved
FROM dbo.tblEmployee e2
INNER JOIN dbo.tblProject p
INNER JOIN dbo.tblBookingForm bf
ON p.ProjectID = bf.ProjectID
ON e2.EmployeeID = p.Scope_PM_EmployeeID
RIGHT OUTER JOIN dbo.tblEmployeeType et
INNER JOIN dbo.tblEmployee e1
ON et.EmployeeTypeID = e1.EmployeeTypeID
INNER JOIN dbo.tblFeedback f
ON e1.EmployeeID = f.ResponsibleEmpID
ON bf.BookingFormID = f.BFID
SQL query - current recordsource for report by Project ID (vueRptFeedbackByProject):
SELECT ProjectID, ProjectName, RespEmp, COUNT(FeedbackID) AS CountReports,
SUM(QtyIssues) AS SumIssues, SUM(EstHoursImpact) AS SumHours
FROM vueRptFeedback
WHERE (DateSubmitted
BETWEEN CONVERT(DATETIME, [Forms]![frmRptFeedback]![txtFromDate], 102)
AND CONVERT(DATETIME, [Forms]![frmRptFeedback]![txtToDate], 102))
GROUP BY ProjectID, RespEmp, ProjectName, DateSubmitted
ORDER BY ProjectID, RespEmp
I know my problem is in the WHERE clause as when I take it out, the report pulls fine but with all records, not the ones between those two dates. Once I can get the report to pull between the txtFromDate and txtToDate, I will probably need to change the OpenReport() to pass the txtFromDate and txtToDate as parameters instead of a Between X and Y, but I keep getting tripped up by syntax on the Recordsource of the report.
Fundamentally, you are conflating two SQL dialects - SQL Server SQL and MS Access SQL. There is no CONVERT() function in Access SQL syntax which appears to be the engine running the recordsource of the report and not the pass-through query, vueRptFeedback, run by MSSQL.
Consider using FORMAT() to align dates to ANSI datetime format: YYYY-MM-DD:
SELECT ProjectID, ProjectName, RespEmp, COUNT(FeedbackID) AS CountReports,
SUM(QtyIssues) AS SumIssues, SUM(EstHoursImpact) AS SumHours
FROM vueRptFeedback
WHERE (DateSubmitted
BETWEEN FORMAT([Forms]![frmRptFeedback]![txtFromDate], "YYYY-MM-DD")
AND FORMAT([Forms]![frmRptFeedback]![txtToDate], "YYYY-MM-DD"))
GROUP BY ProjectID, RespEmp, ProjectName, DateSubmitted
ORDER BY ProjectID, RespEmp
On the VBA side, you can still use Format() as many of Access's SQL functions derived from VBA functions (possibly, this is the reason Access SQL differs from its other RDMS counterparts who adhere to ANSI more due to the need to stay compatible in MS Office VBA context):
Dim strFromDate As String
Dim strToDate As String
strFromDate = Format(txtFromDate.Value, "YYYY-MM-DD")
strToDate = Format(txtToDate.Value, "YYYY-MM-DD")
...
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'";