Just one column from a stored procedure - c#

I have this stored procedure in my SQL Server;
CREATE PROC GetChild
#Child_ID int
AS
SELECT * FROM Children WHERE Child_ID = #Child_ID
I am calling this stored procedure from C#.
I would like to know, if it is possible to call just one column from this table instead of the whole record from C#.?

Assuming you mean return one column, if this is what your stored procedure looks like then no. It will always return all columns back to the client.
You can simply ignore the returned columns that you do not need. Or you can change the stored procedure to only return one column. But as is, it always returns all of them.

You have only have three choices.
Rewrite the Stored procedure to just return the columns you want.
e.g. SELECT foo from Children Where Child_id = #Child_ID
Use a DataReader and just get the columns you want from that
Using a reader directly
while (reader.Read())
`Console.WriteLine("{0}", reader.GetInt32(0));`
Using the Linq extension methods which allows you to filter and sort the results as well as getting just the columns you want.
var List = rdr.Cast<IDataRecord>()
.Select(s => s.GetInt32(0)).ToList();
Abandon the stored procedure and write Select statements against the table. See Pranay's answer

just write below query
select columnname from Children where Child_ID = #Child_ID
columnname- is name of the column you want to retrive
Code for you
SqlConnection mySqlConnection =new SqlConnection("server=(local)\\SQLEXPRESS;database=MyDatabase;Integrated Security=SSPI;");
SqlCommand mySqlCommand = mySqlConnection.CreateCommand();
mySqlCommand.CommandText ="select columnname from Children where Child_ID = #Child_ID";
mySqlCommand .Parameters.Add("#Child_ID", SqlDbType.Int);
mySqlCommand .Parameters["#Child_ID"].Value = idvalue;
mySqlConnection.Open();
SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader(CommandBehavior.SingleRow);
while (mySqlDataReader.Read()){
Console.WriteLine("mySqlDataReader[\" columnname\"] = " +
mySqlDataReader["columnname"]);
}
mySqlDataReader.Close();
mySqlConnection.Close();

Use a SqlDataReader for this:
SqlConnection DbConn = new SqlConnection(YourConnStringHere);
SqlCommand ExecStoredProc = new SqlCommand();
ExecStoredProc.CommandType = CommandType.StoredProcedure;
ExecStoredProc.CommandText = "GetChild";
ExecStoredProc.Connection = DbConn;
ExecStoredProc.Parameters.AddWithValue("#ChildID", YourChildId);
using (DbConn)
{
DbConn.Open();
using (SqlDataReader sdr = ExecStoredProc.ExecuteReader())
{
while(sdr.Read())
// reference your column name like this:
// sdr.GetString(sdr.GetOrdinal("YourColumnName"));
}
}
You can reference any column returned by the SqlDataReader.Read() method. Likewise, if you are looking for an integer value:
int someInt = sdr.GetInt32(sdr.GetOrdinal("YourColumnName"));

From this thread ( Insert results of a stored procedure into a temporary table ), you might want to try OPENROWSET.
First, configure your DB,
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
then, depending on your connection :
SELECT yourcolumnname
FROM
OPENROWSET(
'SQLNCLI',
'server=yourservername;database=yourdbname;uid=youruserid;pwd=youruserpwd',
'EXEC [GetChild] yourchildid'
)
or
SELECT yourcolumnname
FROM
OPENROWSET(
'SQLNCLI',
'server=yourservername;database=yourdbname;Trusted_Connection=yes',
'EXEC [GetChild] yourchildid')
I wouldn't use this solution when retrieving only one line. Performance would be really bad.
For retrieving a great number of lines, this should do the job.

Related

How to fix SQL Injection Issue of truncation of table

Below is the line of code where I truncate table records. The table value is coming from the front end. In my Veracode scan, it is showing SQL injection. How can I avoid this? I cannot create a stored procedure as the connection string is dynamic where I need to truncate this table. Is there another approach?
SqlCommand cmd = connection.CreateCommand();
cmd.Transaction = transaction;
cmd.CommandText = "TRUNCATE TABLE " + tablename;
cmd.ExecuteNonQuery();
You need dynamic sql:
string sql = #"
DECLARE #SQL nvarchar(150);
SELECT #SQL = 'truncate table ' + quotename(table_name) + ';'
FROM information_schema.tables
WHERE table_name = #table;
EXEC(#SQL);";
using (var connection = new SqlConnection("connection string here"))
using (var cmd = new SqlCommand(sql, connection))
{
cmd.Transaction = transaction;
cmd.Parameters.Add("#table", SqlDbType.NVarChar, 128).Value = tablename;
connection.Open();
cmd.ExecuteNonQuery();
}
This is one of very few times dynamic SQL makes things more secure, rather than less. Even better, if you also maintain a special table in this database listing other tables users are allowed to truncate, and use that rather than information_schema to validate the name. The idea of letting users just truncate anything is kind of scary.
Parametrized or not, you can make it only a little more secured in this case. Never totally secured. For this you need
create table TruncMapping in DB where you store
id guid
statement varchar(300)
your data will look like
SOME-GUID-XXX-YYY, 'TRUNCATE TABLE TBL1'
In your front end use a listbox or combobox with text/value like "Customer Data"/"SOME-GUID-XXX-YYY"
In your code use ExecuteScalar to execute Select statement from TruncMapping where id = #1 , where id will be parameterized GUID from combo value
Execute your truncate command using ExecuteNonQuery as you do now but with a retrieved string from previous call.
Your scan tool will most likely choke. If it is still thinking code is unsafe, you can safely point this as false positive because what you execute is coming from your secured DB. Potential attacker has no way to sabotage your "non-tuncatable tables" because they are not listed in TruncMapping tables.
You've just created multi-layered defense against sql injection.
here is one way to hide it from scanning tools
private const string _sql = "VFJVTkNBVEUgVEFCTEU=";
. . . .
var temp = new { t = tablename };
cmd.CommandText =
Encoding.ASCII.GetString(Convert.FromBase64String(_sql)) + temp.t.PadLeft(temp.t.Length + 1);
security by obscurity

C# DataReader: Sql Batch Of Commands And Return Results

When I have multiple select statements that are seperated with an insert statement or some other statement that doesn't return a dataset the last datasets are not returned by the DataReader when calling NextResult.
For instance i have the following sql statement that is to be executed via SqlCommand to the DataReader
select * from testing;
insert into testing (test) values ('testing here');
select * from testing;
And i execute the sql:
IDbCommand command = MyConnection.CreateCommand();
command.CommandText = statement;
var reader = (System.Data.Common.DbDataReader)command.ExecuteReader();
I would like to get back:
resultset for first select statement
records affected for insert statement
result set for second select statement
Instead I receive the first resultset and then when i execute NextResult() the return is false.
If I run two subsequent selects however the resultsets are both returned
ie.
select * from testing
select * from testing2
I've tried just parsing on the ; and excuting the commands seperately.
However, this will not work in the long run because eventually I will have the use case to submit an anonymous query or create a stored procedure that would have semicolons in the command.
How can iterate through a DataReader that has mixed results of data and queries that do not have a return?
I ended up resorting to using a DbDataAdapter and loading the corresponding data into memory, instead of using a DbDataReader. For my application this worked okay.
The DataAdapter handles obtaining both DataTables and also runs the inserts, etc.
Here is a code snippet similar to what i ended up doing:
var command = Connection.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = statement;
DataSet set = new DataSet();
var da = CreateDataAdapter(connection);
da.SelectCommand = command;
var recordsEffected = da.Fill(set);
foreach (DataTable newTable in set.Tables){
//do stuff with data returned
}
You should temporarily store your results from the first query before inserting your testing values.
SQL Server:
DECLARE #temp TABLE
([test] VARCHAR(20)) -- change type depending on your needs.
INSERT INTO #temp
SELECT *
FROM testing
SELECT * FROM #temp -- first result
SELECT * FROM testing
PostgreSQL:
CREATE TEMP TABLE temp1 ON COMMIT DROP AS
SELECT *
FROM testing
INSERT INTO testing (test) VALUES ('testing here');
SELECT * FROM temp1 -- first result
SELECT * FROM testing
Take a look here, at the SqlDataReader.NextResult method...
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.nextresult.aspx
IDbCommand command = MyConnection.CreateCommand();
command.CommandText = statement;
var reader = command.ExecuteReader();
while(reader.Read()){
//Logic for first result
}
reader.NextResult();
while(reader.Read()){
//Logic for second result
}

Calling a stored procedure and checking the return value

I have a stored procedure called pat_selectPatientById and that stored procedure returns a true or false using ISNULL(#isEqual, 0) as IsProviderSameAsPCP.
I am trying to call this stored procedure using a C# method by calling Application.WebService.ExecuteQuery("pat_selectPatientById"). But I'm not having any luck - can someone point me in the right direction?
Thanks a lot guys
Code:
declare #isEqual bit =
(select
top 1 1 as IsEqual
from
Patient p
inner join
[Resource] r on p.ProviderId = r.ResourceId
where
PatientId = #PatientId
and p.PrimaryCareProviderId = r.RefPhysId)
You need to return the value from your stored procedure.
SELECT #isEqual
Aside that you need a SqlConnection object and a SqlCommand object to invoke the stored procedure.
conn = new SqlConnection(connectionString);
conn.Open();
SqlCommand cmd = new SqlCommand("IsProviderSameAsPCP", conn);
cmd.CommandType = CommandType.StoredProcedure;
rdr = cmd.ExecuteReader();
You can then use the rdr object to loop through the result set.
You can find your connection string at:
http://www.connectionstrings.com/
I.e. for SQL Server 2008:
string connectionString = "Server=myServerAddress;Database=myDataBase;Trusted_Connection=True;";
You need to return the value in a select. Next line in your proc needs to be
select #isEqual
ie..
declare #isEqual bit =
(select
top 1 1 as IsEqual
from
Patient p inner join [Resource] r
on p.ProviderId = r.ResourceId
where
PatientId = #PatientId
and p.PrimaryCareProviderId = r.RefPhysId)
select #isEqual
ExecuteScalar is the command in C# you are looking for. You could also use an output parameter on your stored proc if you have multiple values and don't want to return a table output.

Displaying data from SQL database in C# WinForm controls (textBox, comboBox, label)

I have a performance problem with displaying data from an SQL database in my application. The problem is that I have a large number of parameters that I need to display (customers personal data, his current statistics etc.).
So far I've used either SqlCommand.ExecuteScalar (for single parameters), or DataTable.Rows[].ItemArray.GetValue() (for multiple parameters - I fill the DataTable with SqlDataAdapter whose query withdraws the necessary data from the database) and assigned their values to the appropriate control. Assuming that command is an SqlCommand type:
For single parameter
command.CommandText = "SELECT Parameter1 FROM MyTable WHERE Condition = Value";
textBox1.Text = command.ExecuteScalar().ToString();
For multiple parameters (SDA is a SqlDataAdapter):
command.CommandText="SELECT Parameter1 - ParameterN FROM MyTable WHERE Condition = Value";
SDA.SelectCommand = command;
SDA.Fill(MyDataTable);
textBox1.Text = MyDataTable.Rows[0].ItemArray.GetValue(0).ToString();
comboBox1.Text = MyDataTable.Rows[0].ItemArray.GetValue(1).ToString();
/*
I repeat similar lines of code for each parameter and display it in the appropriate control.
*/
This approach works correctly but when I have a large number of parameters (20+), it works very slowly.
Is there a more efficient way to display these amounts of data, and how would I implement it?
Thank you
Probably, with the second example, a SqlDataReader will perform better because you read the values just one time, while with a DataAdapter, you need to load the DataTable and then loop over the rows of the table (Effectively reading data two times).
command.CommandText="SELECT Field1,...,FieldN FROM MyTable WHERE Condition = Value";
SqlDataReader reader = command.ExecuteReader();
while(reader.Read())
{
// Of course this works correctly just if your query returns one row....
textBox1.Text = reader.GetString(0);
comboBox1.Text = reader.GetString(n);
}
You could also try with the Field<T> extension for the DataRow
command.CommandText="SELECT Field1,...,FieldN FROM MyTable WHERE Condition = Value";
SqlDataAdapter SDA = new SqlDataAdapter(command);
SDA.Fill(MyDataTable);
textBox1.Text = MyDataTable.Rows[0].Field<string>("Field1");
comboBox1.Text = MyDataTable.Rows[0].Field<string>("FieldN");
However, I think that the real performance gain would be in the query that you submit to the database engine and in the correct working of indexes on your tables.
Try to retrieve the minimun number of rows possible, search on indexed fields and/or change to a stored procedure.
here i had write sample stored procedure in wich you can get idea...
you can pass as amny parameter as you can in xml format and insert into temp table...
now you have table with value Name/value pair means Paramater name /value....
now you can do your furteher work...
/*
EXEC wa_TempGetDaya '<SampleXML>
<tblXML><AccountID>3</AccountID><Code>11</Code><Description>Leptospiral infect NEC</Description></tblXML>
</SampleXML>'
*/
CREATE PROCEDURE wa_TempGetDaya
(
#ParaXML NVARCHAR(MAX)
)
AS
SET NOCOUNT ON
BEGIN
DECLARE #AccountID INT
DECLARE #MyXML XML
SET #MyXML = #ParaXML
IF OBJECT_ID('tempdb..#TempData') IS NOT NULL
DROP TABLE #TempData
SELECT * INTO #TempData
FROM (
SELECT
Parse.value('(AccountID)[1]', 'INT') AS 'AccountID',
Parse.value('(Code)[1]', 'Varchar(100)') AS 'Code',
Parse.value('(Description)[1]', 'varchar(1000)') AS 'Description'
FROM
#MyXML.nodes('/SampleXML/tblXML') AS YourData(Parse)
) AS tbl
declare #para1 varchar(20)
declare #para2 varchar(20)
declare #para3 varchar(20)
SELECT #para1 =AccountID ,#para2 =Code,#para3 =Description from #TempICD
END

Return last inserted ID without using a second query

I'm working on an ASP.NET project (C#) with SQL Server 2008.
When I insert a row into a table in the database, I would like to get the last inserted ID, which is the table's IDENTITY (Auto Incremented).
I do not wish to use another query, and do something like...
SELECT MAX(ID) FROM USERS;
Because - even though it's only one query - it feels lame...
When I insert something I usually use ExecuteNonQuery(), which returns the number of affected rows.
int y = Command.ExecuteNonQuery();
Isn't there a way to return the last inserted ID without using another query?
Most folks do this in the following way:
INSERT dbo.Users(Username)
VALUES('my new name');
SELECT NewID = SCOPE_IDENTITY();
(Or instead of a query, assigning that to a variable.)
So it's not really two queries against the table...
However there is also the following way:
INSERT dbo.Users(Username)
OUTPUT inserted.ID
VALUES('my new name');
You won't really be able to retrieve this with ExecuteNonQuery, though.
You can return the id as an output parameter from the stored procedure, e.g. #userId int output
Then, after the insert, SET #userId = scope_identity()
even though it's only one query - it feels lame...
It actually is also wrong as you can have multiple overlapping iserts.
That is one thing that I always fuind funny - people not reading the documentation.
SELECT SCOPE_IDENTITY()
returns the last identity value generated in a specific scope and is syntactically correct. It also is properly documented.
Isn't there a way to return the last inserted ID without using another query?
Yes. Ask for the number in the saame SQL batch.
INSERT (blablab9a); SELECT SCOPE_IDENTITY ();
as ONE string. ExecuteScalar.
You can have more than one SQL statement in one batch.
If you want to execute query from C# code & want to get last inserted id then you have to find the following code.
SqlConnection connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
connection.Open();
string sql = "Insert into [Order] (customer_id) values (" + Session["Customer_id"] + "); SELECT SCOPE_IDENTITY()";
SqlCommand cmd = new SqlCommand();
cmd.Connection = connection;
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
var order_id = cmd.ExecuteScalar();
connection.Close();
Console.Write(order_id);

Categories

Resources