This question already has answers here:
How to run multiple SQL commands in a single SQL connection?
(9 answers)
How do I return multiple result sets with SqlCommand?
(7 answers)
Closed 5 years ago.
I'm having trouble to figure out how to get more then one SQL query to work in C#. I have something like this:
breakControlq.CommandText =
#"SELECT something as q1 From table" +
"SELECT somethingelse as q2 FROM table where this = this";
breakControlq.CommandType = CommandType.Text;
breakControlq.Connection = hd01Connect;
try
{
hd01Connect.Open();
breakControlRead = breakControlq.ExecuteReader();
while (breakControlRead.Read())
{
textBox1.AppendText(breakControlRead["q1"].ToString());
textBox2.AppendText(breakControlRead["q2"].ToString());
}
catch(System.Data.SqlClient.SqlException ex)
{
MessageBox.Show(ex.Message, "Connection Error");
}
Is this possible to do?
Do I have to repeat the connection/command to every single query?
I'm pretty new at this and some of you will tell that this has already been answered somewhere, but I searched so many posts that I'm more confused then when a started to search for the solution.
You are looking for .NextResult(). The .Read() method changes to the next row in the current grid; .NextResult() moves to the next grid:
while (breakControlRead.Read())
{
// process rows from first grid
}
if(breakControlRead.NextResult()) {
while (breakControlRead.Read())
{
// process rows from second grid
}
}
Alternatively; "dapper" would expose this via .QueryMultiple():
using(var multi = conn.QueryMultiple(sql, args)) {
var s = multi.Read<string>().AsList(); // items from first grid
var i = multi.ReadSingle<int>(); // items from second grid
// ...
}
Note! You do need to ensure that your two queries are separated by either whitespace or ;; in your case this would be fine:
#"SELECT something as q1 From table
SELECT somethingelse as q2 FROM table where this = this";
(note whitespace)
alternative and more correctly:
#"SELECT something as q1 From table;
SELECT somethingelse as q2 FROM table where this = this;";
or:
#"SELECT something as q1 From table;SELECT somethingelse as q2 FROM table where this = this;";
I'm having trouble to figure out how to get more then one SQL query to
work in C#
Well, wrap both your SQL statement in a stored procedure and call that procedure from your application code like
create procedure usp_data
as
begin
SELECT something as q1 From table;
SELECT somethingelse as q2 FROM table where this = this;
end
See How to: Execute a Stored Procedure that Returns Rows for more information
Related
This question already has answers here:
Retrieve List of Tables from Specific Database on Server C#
(7 answers)
Closed 7 years ago.
How can I make a code to get the number of tables to a link textbox in a given database? I'm using visual studio 2013 and I'm new to this. I used database server ms sql.
public static List<string> GetTables(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
DataTable schema = connection.GetSchema("Tables");
List<string> TableNames = new List<string>();
foreach (DataRow row in schema.Rows)
{
TableNames.Add(row[0].ToString());
}
return TableNames;
}
}
To be honest, i don't understand the question. You want the count of tables in a given database. The database is specified by the connection-string. You have already the code that returns a DataTable with all tables.
So here is the missing piece. Since connection.GetSchema("Tables") also returns views, if you want to count both you are ready with:
DataTable schema = connection.GetSchema("Tables");
int tableAndViewCount = schema.Rows.Count;
If you only want to count tables and exclude views:
int tableCount = schema.AsEnumerable().Count(t => t.Field<string>("TABLE_TYPE") == "BASE TABLE");
Get count of tables using the below query , just add that query in your application.
SELECT COUNT(*) from information_schema.tables
WHERE table_type = 'base table'
Try this Query
select * from sys.tables
I am using C# in Visual Studio 2013 and SQL Server 2012.
When the user of my ASP.NET web form enters a newline-separated list of codes and clicks submit, the code behind should read the values, concatenate them into a comma-delimited string, and pass the string to a method that calls a stored proc. The stored proc parses out the values and sets the active field to 1 on each record with a matching code.
The Product table is defined as:
id (PK, int, not null),
name (varchar(20), not null),
code (varchar(20), null),
active (bit, not null)
The Product table contains the following five records:
id name code active
-- ---- ---- ------
1 Product 1 AAA 0
2 Product 2 BBB 0
3 Product 3 CCC 0
4 Product 4 DDD 0
5 Product 5 EEE 0
I created the following stored proc:
CREATE PROCEDURE [dbo].[MarkListAsActive]
#codeList varchar(MAX)
AS
UPDATE
dbo.Product
SET
active = 1
WHERE
code IN (SELECT val FROM dbo.f_split(#codeList, ','))
dbo.f_split handles parsing the comma-delimited string. I copied it from this post: https://stackoverflow.com/a/17481595/2677169
If I execute the stored proc in SQL Server Management Studio, all five records get updated (as expected).
DECLARE #return_value int
EXEC #return_value = [dbo].[MarkListAsActive]
#codeList = N'AAA,BBB,CCC,DDD,EEE'
SELECT 'Return Value' = #return_value
GO
However, if I call the stored proc from the code behind of my .aspx page, only the last item in the list gets marked as active.
protected void SubmitButton_Click(object sender, EventArgs e)
{
string[] codeArray;
char separator = '\n';
OutputLabel.Text = "";
codeArray = ProductCodeTextBox.Text.Split(separator);
OutputLabel.Text += "The products with the following codes were marked as active:<br />";
string codes = "";
// TODO: Replace with regex that changes newlines to commas
for (int i = 0; i < codeArray.Length; i++)
{
codes += codeArray[i] + ",";
OutputLabel.Text += codeArray[i] + "<br />";
}
codes = codes.Substring(0, codes.Length - 1);
Utilities.Log(codes);
DataAccess.MarkListAsActive(codes);
}
public static void MarkListAsActive(string codeList)
{
try
{
string connectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand("[dbo].[MarkListAsActive]", conn)
{
CommandType = CommandType.StoredProcedure
})
{
conn.Open();
command.Parameters.Add("#codeList", codeList);
command.ExecuteNonQuery();
conn.Close();
}
}
catch (Exception ex)
{
Utilities.Log(String.Format("Error in MarkListAsActive: {0}\n{1}", ex.Message, ex.StackTrace));
}
return;
}
Note that I verified that the string being passed to MarkListAsActive() is correct.
Another approach: I tried looping through the codeArray and calling MarkListAsActive() for each item. Even this brute force (and inefficient) approach only updated the last item in the array.
Yet another aproach: I also tried a table valued parameter, but it too only updated the record corresponding to the last item in the input.
Thank you in advance for your help.
Change the IN clause to (SELECT val FROM dbo.f_split(#codeList, ',') where val is not null).
If that doesn't work follow these steps:
(You should know how to debug something like this anyway.)
First, use SQL Profiler to see what exactly is submitted to the database. See here for how to do that - its not as bad as it looks and is invaluable. If not what is expected, you have a problem on the front end.
Second, if the call to the database looks good then take the parameter you see in SQL Profiler and execute dbo.f_split() using it to see if you get back what you think you should.
Last, change your UPDATE statement into a SELECT statement and run it with what you did in the second step and see if you get back something that looks correct.
One of those steps will not return what is expected and that will lead you to the problem.
Your where clause is incorrect. You cannot do
... code in (select val ...
You need to join the result from the f_split function to the table.
For example:
UPDATE p
SET p.active = 1
FROM dbo.Product p inner join dbo.f_split(#codeList, ',') f
WHERE p.code = f.val;
This question already has answers here:
Parameterize an SQL IN clause
(41 answers)
Closed 9 years ago.
In my application written in C# , I am writing a SQL query. Following is the query
SELECT [Resource No_] where [Resource No_] In (#resources)
#resources is user input parameters having one or more that one strings.
My query is failing without showing an error
According to me, query is failing because in #resources parameter following is being passed
"'123,'124','125'"
(there are 2 inverted commas in the beginning and at the end and that is failing my query).
[Resource No_] is of type NVARCHAR in the database.
After Googling, I have found some help on this topic but all are applicable when [Resource No_] is of type Integer
While I don't agree with the selected answer (or many of the tricky answers) for the "duplicate question", here is an answer to it which shows an approach very similar with my following recommendation.
(I've voted to close this question as a duplicate, because there are such answers, even if buried.)
Only one SQL value can be bound to any given placeholder.
While there ways to send all the data as "one value", I'd recommend creating the placeholders dynamically: it's simple, clean, and will work reliably in most cases.
Consider this:
ICollection<string> resources = GetResources();
if (!resources.Any()) {
// "[Resource No_] IN ()" doesn't make sense
throw new Exception("Whoops, have to use different query!");
}
// If there is 1 resource, the result would be "#res0" ..
// If there were 3 resources, the result would be "#res0,#res1,#res2" .. etc
var resourceParams = string.Join(",",
resources.Select((r, i) => "#res" + i));
// This is NOT vulnerable to classic SQL Injection because resourceParams
// does NOT contain user data; only the parameter names.
// However, a large number of items in resources could result in degenerate
// or "too many parameter" queries so limit guards should be used.
var sql = string.Format("SELECT [Resource No_] where [Resource No_] In ({0})",
resourceParams);
var cmd = conn.CreateCommand();
cmd.CommandText = sql;
// Assign values to placeholders, using the same naming scheme.
// Parameters prevent SQL Injection (accidental or malicious).
int i = 0;
foreach (var r in resources) {
cmd.Parameters.AddWithValue("#res" + i, r);
i++;
}
Use a user defined table type to accept your parameter, then a JOIN clause in your select to limit the results set. See http://social.msdn.microsoft.com/Forums/en-US/2f466c93-43cd-436d-8a7c-e458feae71a0/how-to-use-user-defined-table-types
Do something like
resources.Aggregate(r1, r2 => r1 + "', '" + r2 + "'")
and pass the list in one string.
This question already has answers here:
List of tables used in an SQL Query
(5 answers)
Closed 9 years ago.
I need extract from simple string that represent an sql query the tables that are used on the query without execute the query itself in C#.
Example:
string strQuery = "SELECT * FROM table1 LEFT JOIN (SELECT * FROM table2) tt WHERE tt.name IN (SELECT name FROM table3)";
ArrayList arrUsedTables = GetUsedTablesFromQuery(strQuery);
and after this line the object arrUsedTables would contain:
table1,table2,table3
Remember that the query may be much complicated!
Without going to the DB you can't know for certain the names of the tables used in the query.
What if your query uses a view or a stored procedure?
Without consulting the database, these are transparent to the consumer.
The only way to be certain is to query the list of the tables from the database and then to attempt to parse them from your inline sql.
You will have to add references and directives for the following assemblies:
using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;
using System.IO;
Then, you may create the GetUsedTablesFromQuery method:
private static ArrayList GetUsedTablesFromQuery(string strQuery)
{
var parser = new TSql100Parser(true);
IList<ParseError> errors = new List<ParseError>();
using (TextReader r = new StringReader(strQuery))
{
var result = parser.GetTokenStream(r, out errors);
var tables = result
.Select((i, index) => (i.TokenType == TSqlTokenType.From) ? result[index + 2].Text : null)
.Where(i => i != null)
.ToArray();
return new ArrayList(tables);
}
}
You can certainly use a SQL parser such as ANTLR, as described in this question and answer, in order to get a full parse of the SQL, and then extract the table names.
Another option is to execute some raw SQL to get the execution plan of the query (using the instructions here). The execution plan is in XML, and then you can use Linq to XML to query the plan for all Table attributes on any ColumnReference tag.
I have a question regarding Oracle bind variables and select statements.
What I would like to achieve is do a select on a number different values for the primary key. I would like to pass these values via an array using bind values.
select * from tb_customers where cust_id = :1
int[] cust_id = { 11, 23, 31, 44 , 51 };
I then bind a DataReader to get the values into a table.
The problem is that the resulting table only contains a single record (for cust_id=51). Thus it seems that each statement is executed independently (as it should), but I would like the results to be available as a collective (single table).
A workaround is to create a temporary table, insert all the values of cust_id and then do a join against tb_customers. The problem with this approach is that I would require temporary tables for every different type of primary key, as I would like to use this against a number of tables (some even have combined primary keys).
Is there anything I am missing?
Not asking the question as to why you would want to do this to begin with. Shouldn't the sql statement be something like
select * from tb_customers where cust_id = 11 or 23 or ...
Edit:
I am limited in Oracle but when I look at the documentation I think that you might have to do something like this:
variable i number
exec :i := 11
select * from tb_customers where cust_id = :i
This would allow you to take advantage of binding. You will have to add each record return to your own collection since it will still only return one at a time.
I know this was asked a while ago but not a brilliant answer.
I would do something like this - please excuse the crude psudo code
string bindList = "";
for(int ii=0;ii<cust_id.count;++ii)
{
if(ii == 0)
{
bindList += ":" + ii;
}
else
{
bindList += ",:" + ii;
}
OracleParameter param = new OracleParameter();
param.dbType = types.int;
param.value = cust_id[ii];
command.Parameters.Add(param);
}
query = "select * from tb_customers where cust_id in(" + bindList + ")";
So then query ends up having in(:1,:2,:3,etc) and each of these are bound separately.
There is also a similar question here: OracleParameter and IN Clause