Fetching Single Row in PL/SQL - c#

I am trying to create a new procedure in Oracle SQL Developer client. This procedure will fetch a single row on the basis of one condition.
My procedure code is as follow:-
create or replace PROCEDURE GETUSERKEYS
(
USERNAME IN NVARCHAR2
, STATUS OUT NUMBER
, TEMPTB OUT ClientKey%rowtype
) AS
BEGIN
SELECT * INTO TEMPTB FROM ClientKey WHERE ClientKey.USERNAME=USERNAME;
STATUS:=1;
END GETUSERKEYS;
Here is my C# code:
using (OracleConnection connection = new OracleConnection(ConnectionString))
{
using (OracleCommand cmd = new OracleCommand("GetUserKeys", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter username = new OracleParameter();
username.OracleDbType = OracleDbType.NVarchar2;
username.ParameterName = "Username";
username.Direction = ParameterDirection.Input;
username.Value = Username;
cmd.Parameters.Add(username);
OracleParameter status = new OracleParameter();
status.OracleDbType = OracleDbType.Int32;
status.ParameterName = "Status";
status.Direction = ParameterDirection.Output;
cmd.Parameters.Add(status);
if (connection.State == ConnectionState.Open)
connection.Close();
connection.Open();
cmd.ExecuteNonQuery();
DataSet dataset = new DataSet();
OracleDataAdapter da = new OracleDataAdapter(cmd);
da.Fill(dataset);
_id = (int)cmd.Parameters["Status"].Value;
if (_id > 0)
{
if (dataset.Tables[0] != null && dataset.Tables[0].Rows.Count != 0)
{
_key = new ClientKey();
_key.ClientId = dataset.Tables[0].Rows[0]["ClientId"].ToString();
_key.ClientSecret = dataset.Tables[0].Rows[0]["ClientSecret"].ToString();
_key.ClientKeyId = int.Parse(dataset.Tables[0].Rows[0]["ClientKeyID"].ToString());
_key.Username = dataset.Tables[0].Rows[0]["Username"].ToString();
_key.CreateOn = Convert.ToDateTime(dataset.Tables[0].Rows[0]["CreateOn"].ToString());
}
}
}
}
I am not able to figure out a way to return a row from a table based on condition.
I am new to Oracle.

The problem is Oracle's C# client does not support %ROWTYPE , so you need to use a workarounds.
The simplest solution for you would be to use SYS_REFCURSOR , which maps to an ODBC ResultSet. One record is still a set. You probably don't want to go down the road of building Oracle user-defined types.
This Oracle tutorial provides a starting point for using SYS_REFCURSOR with ODP.Net.

Related

How to write and consume oracle procedure in .Net Core 3.1

As I am new in Oracle and don't have much experience how to create & consume oracle procedure. Can someone please help me to fix my code below.
Procedure
CREATE OR REPLACE PROCEDURE sprocGetTableColumns (
p_table_name in user_tab_columns.table_name%type,
po_userdisp_cur OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN po_userdisp_cur
FOR SELECT u.Column_Name,
u.Data_Type,
u.Nullable
FROM USER_TAB_COLUMNS u
WHERE u.table_name = p_table_name order by column_id
END sprocGetTableColumns;
C# Code
using (OracleConnection conn = new OracleConnection(templateSettingModel.ConnectionString))
{
OracleCommand objCmd = new OracleCommand();
objCmd.Connection = conn;
objCmd.CommandText = "sprocGetTableColumns";
objCmd.CommandType = CommandType.StoredProcedure;
objCmd.Parameters.Add("#tableName", OracleDbType.Varchar2).Value = 20;
objCmd.Parameters.Add("P_COLUMN_NAMES", OracleDbType.Varchar2).Direction = ParameterDirection.Output;
await conn.OpenAsync();
var dataReader = await objCmd.ExecuteReaderAsync(CommandBehavior.CloseConnection);
while (dataReader.Read())
{
var item = new TemplateFieldMappingModel
{
ColumnName = CommonHelper.To<string>(dataReader["COLUMN_NAME"]),
DataType = CommonHelper.To<string>(dataReader["DATA_TYPE"]),
IsNullable = CommonHelper.To<bool>(dataReader["IS_NULLABLE"])
};
// set the field name to be the same as the column name
item.FieldName = item.ColumnName;
if (!item.IsNullable)
item.IsRequired = true;
models.Add(item);
}
await dataReader.CloseAsync();

Hello everyone.I want to import values into sql from access database but except previously added records from access

Getting values from my access database into DataTable table
string accessconst = "Provider = Microsoft.Jet.OLEDB.4.0; Data Source = C:/Program Files (x86)/BALLBACH/Database/Messdaten.mdb";
DataTable table = new DataTable();
using (OleDbConnection conn = new OleDbConnection(accessconst))
{
using (OleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM Messdaten", conn))
{
da.Fill(table);
}
}
Getting values from my sql database into DataTable tablesql
string sqlconstr = "sqlconstr";
DataTable tablesql = new DataTable();
using (SqlConnection conn = new SqlConnection(sqlconstr))
{
using (SqlDataAdapter da = new SqlDataAdapter("SELECT p1 FROM UMP", conn))
{
da.Fill(tablesql);
}
}
Now I want to import the values into the sql db from the access db except the previously added records from the access db. How can I do this?
//HERE IS THE PROBLEM
using (SqlConnection con = new SqlConnection("MyConnectionStr "))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "INSERT INTO UMP VALUES (#p1, #p2, #p3)";
cmd.Connection = con;
cmd.Parameters.Add("#p1", SqlDbType.NVarChar, 50);
cmd.Parameters.Add("#p2", SqlDbType.NVarChar, 50);
cmd.Parameters.Add("#p3", SqlDbType.NVarChar, 50);
con.Open();
for (int i = 0; i < table.Rows.Count; i++)
{
cmd.Parameters["#p1"].Value = table.Rows[i][0];
cmd.Parameters["#p2"].Value = table.Rows[i][1];
cmd.Parameters["#p3"].Value = table.Rows[i][2];
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
break;
}
}
}
}
what i would suggest is taking all access data and insert it into a temporary table.
then insert the data based on a left join, perform the insert.
your code would then look something like this...
//data from access
private void insertValues(DataTable table)
{
using (SqlConnection con = new SqlConnection("MyConnectionStr "))
{
using (SqlCommand cmd = con.CreateCommand())
{
createTable();
//note changed the insert to tmp table.
cmd.CommandText = "INSERT INTO UMP_TMP VALUES (#p1, #p2, #p3)";
cmd.Connection = con;
cmd.Parameters.Add("#p1", SqlDbType.NVarChar, 50);
cmd.Parameters.Add("#p2", SqlDbType.NVarChar, 50);
cmd.Parameters.Add("#p3", SqlDbType.NVarChar, 50);
con.Open();
for (int i = 0; i < table.Rows.Count; i++)
{
cmd.Parameters["#p1"].Value = table.Rows[i][0];
cmd.Parameters["#p2"].Value = table.Rows[i][1];
cmd.Parameters["#p3"].Value = table.Rows[i][2];
try
{
cmd.ExecuteNonQuery();
}
catch (Exception)
{
break;
}
}
//merge the data from within sql server
mergeTable();
//drop the temporary table
dropTable();
}
}
}
private void createTable(){
issueStatement("create table UMP_TMP(p1 varchar(50), p2 varchar(50), p3 varchar(50));");
}
private void dropTable()
{
issueStatement("drop table UMP_TMP;");
}
private void mergeTable()
{
issueStatement("insert into UMP select ump_tmp.p1,ump_tmp.p2,ump_tmp.p3 from UMP_TMP left join UMP on UMP_TMP.p1 = UMP.P1 and UMP_TMP.p2 = UMP.P2 and UMP_TMP.p3 = UMP.P3 WHERE ump.p1 is null and ump.p2 is null and ump.p3 is null");
}
private void issueStatement(string command)
{
using (SqlConnection con = new SqlConnection("MyConnectionStr "))
{
using (SqlCommand cmd = con.CreateCommand())
{
con.Open();
cmd.CommandText = command;
//add error handling
cmd.ExecuteNonQuery();
}
}
}
Expanding on #Kirk's response, your ultimate goal that solves the problem is to perform the left join operation on your two tables. You will have needed to identified what columns on each table join the data, and what columns make a row unique.
You can do this in any of the 3 environments your working in a) Access, b) SQL, c) .NET.
I would recommend SQL, its the best at it. (plus your only transferring one set of data through the client (the access data)) So get all the data into SQL tables, and then execute a SQL stored procedure to do the left join and update the SQL data table.
You can work out the SQL work with just Management Studio, the queries etc. Once you've built the stored procedure (and anything else you might need like views). Your .NET code is then two simple parts, 1) upload the Access data 2) call the proc to merge it.
Final point, if your .net's client only purpose is this upload and merge, then you don't need it at all. SQL Servers SSIS can do all of this, and depending on the size of data involved might be the much better choice.

DataTable Is Empty

I am attempting to run a stored procedure and add the results to a data table. My stored procedure executes as it should, bc if I query the table the results are stored in from SSMS - the accurate results are there. However, my code below will produce numberofrecords = 0 everytime!
What did I set-up incorrectly in this syntax below?
using (conn = new SqlConnection(SQLConn))
{
using (cmd = new SqlCommand(storedprocname, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.VarChar, 100);
cmd.Parameters.Add("d1", SqlDbType.Date, 100);
cmd.Parameters.Add("d2", SqlDbType.Date, 100);
cmd.Parameters["#Name"].Value = cboNames.Text.ToString();
cmd.Parameters["d1"].Value = dtpd1.Value.ToString("MM/dd/yyyy");
cmd.Parameters["d2"].Value = dtpd2.Value.ToString("MM/dd/yyyy");
cmd.Parameters.Add("#Dolla", SqlDbType.VarChar, 100);
cmd.Parameters["#Dolla"].Value = cboDolla.Text.ToString();
using (da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
int numberOfRecords = 0;
numberOfRecords = dt.Select().Length;
MessageBox.Show(numberOfRecords.ToString());
}
And these are my class variable declarations:
public static SqlCommand cmd;
public static SqlDataAdapter da;
public static DataSet ds = new DataSet();
public static DataTable dt = new DataTable();
EDIT
And this is my stored proc which produces roughly 32 rows
ALTER Procedure [dbo].[TestParamQuery]
(
#Name varchar(max)
,#d1 varchar(100)
,#d2 varchar(100)
,#dolla varchar(500)
)
As
Select
EmployeeName
,EmployeeNumber
,CAST(hiredate As Date) [hire date]
,saleamount
FROM [TestDB].[dbo].[SalesFigs]
WHERE employeename = #Name
AND hiredate between #d1 AND #d2
AND saleamount >= #dolla
EDIT 2
This is how I execute the stored procedure to ensure it is returning the results I want from directly inside SSMS
USE [TestDB]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[TestParamQuery]
#Name = N'Sam Wise',
#d1 = N'03/01/2016',
#d2 = N'01/30/2016',
#Dolla = N'1000'
SELECT 'Return Value' = #return_value
GO
Unfortunately, SqlCommand does not have an easy method or property for converting the command to a string, with all parameters and values included. I have used a method like this in the past to make debugging commands easier:
public static string PrintCommand(this SqlCommand command){
if (command == null) throw new ArgumentNullException("command");
var sb = new StringBuilder();
sb.AppendLine(command.CommandText);
foreach (var p in command.Parameters){
sb.AppendLine("\t" + p.ParameterName + ": " + p.Value);
}
return sb.ToString();
}
It should output a string like this:
"dbo.MyCommandName
#Name: myNameParameterValue
d1: 01/01/2016
d2: 02/02/2016
#Dolla: myDollaValue"
You can then invoke it like this, and check the value in a step-thru debugger.
using (conn = new SqlConnection(SQLConn))
using (cmd = new SqlCommand(storedprocname, conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.VarChar, 100);
cmd.Parameters.Add("d1", SqlDbType.Date, 100);
cmd.Parameters.Add("d2", SqlDbType.Date, 100);
cmd.Parameters["#Name"].Value = cboNames.Text.ToString();
cmd.Parameters["d1"].Value = dtpd1.Value.ToString("MM/dd/yyyy");
cmd.Parameters["d2"].Value = dtpd2.Value.ToString("MM/dd/yyyy");
cmd.Parameters.Add("#Dolla", SqlDbType.VarChar, 100);
cmd.Parameters["#Dolla"].Value = cboDolla.Text.ToString();
//Get a text representation here:
var text = cmd.PrintCommand();
//Put a breakpoint here to check the value:
using (da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
int numberOfRecords = 0;
numberOfRecords = dt.Select().Length;
MessageBox.Show(numberOfRecords.ToString());
}
Not sure why you cannot get values. But anyway please try this approach:
using (conn = new SqlConnection(SQLConn))
using (cmd = new SqlCommand(storedprocname, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Name", cboNames.Text);
cmd.Parameters.AddWithValue("d1", dtpd1.Value.ToShortDateString();
cmd.Parameters.AddWithValue("d2", dtpd2.Value.ToShortDateString();
cmd.Parameters.AddWithValue("#Dolla", cboDolla.Text);
using (da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
var numberOfRecords = dt.Rows.Count;
MessageBox.Show(numberOfRecords);
}

ASP.Net C# - Passing a variable into MySQL query

So I want to create a line graph with data from a MySQL table and I've managed to draw one using the code below.
However, I want to pass a variable 'moduleID' to the MySQL query and I have done so, however, I'm not sure if this is the most appropriate way to do so. Should I pass a parameter instead and if so, how do I do that?
protected void chart(int moduleID)
{
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
MySqlConnection conn = new MySqlConnection(connStr);
string comm = "SELECT * FROM scores WHERE module_id=" + moduleID.ToString();
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(comm, conn);
DataSet ds = new DataSet();
Chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Minimum = 1;
Chart1.ChartAreas["ChartArea1"].AxisX.LabelStyle.Enabled = false;
Chart1.ChartAreas["ChartArea1"].AxisX.Title = "time";
Chart1.ChartAreas["ChartArea1"].AxisY.Minimum = 0;
Chart1.ChartAreas["ChartArea1"].AxisY.Maximum = 100;
Chart1.ChartAreas["ChartArea1"].AxisY.Title = "%";
Chart1.ChartAreas["ChartArea1"].AxisY.TextOrientation = TextOrientation.Horizontal;
try
{
conn.Open();
dataAdapter.Fill(ds);
Chart1.DataSource = ds;
Chart1.Series["Series1"].YValueMembers = "score";
Chart1.DataBind();
}
catch
{
lblError.Text = "Database connection error. Unable to obtain data at the moment.";
}
finally
{
conn.Close();
}
}
You are right. Concatenating strings to form a query is prone to SQL injection. Use parameters like:
string comm = "SELECT * FROM scores WHERE module_id=#module_id";
MySqlCommand mySqlCommand = new MySqlCommand(comm,conn);
mySqlCommand.Parameters.Add(new MySqlParameter("#module_id", module_id));
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(mySqlCommand);
You should also enclose your connection and command object with using statement. This will ensure proper disposal of resource.
Also an empty catch is very rarely useful. You should catch specific exception first and then the base exception Exception in an object. Use that object to log the exception information or show in your error message. This will provide you help in debugging your application.
Step1: Create stored Procedure
CREATE PROCEDURE SelectScore
(#moduleID NCHAR(50))AS
SELECT * FROM scores WHERE module_id=#moduleID
Step2: Call the stored Procedure from Code
string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr )) {
conn.Open();
// 1. create a command object identifying the stored procedure
SqlCommand cmd = new SqlCommand("SelectScore", conn);
// 2. set the command object so it knows to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which will be passed to the stored procedure
cmd.Parameters.Add(new SqlParameter("#moduleID ", moduleID ));
// execute the command
using (SqlDataReader rdr = cmd.ExecuteReader()) {
// iterate through results, printing each to console
while (rdr.Read())
{
..
}
}
}

How to call Oracle stored procedure which returns ref cursor

I am trying to call Oracle stored procedure which returns ref cursor, and i need to generate tree view from that returned data. I am new at this and i have two problems.
First problem is that i am not able to call that procedure. I am getting this error: "wrong number or types of arguments in call to 'OBJECT_HIERARCHY'"
And my second problem is that i don't understand how am i gonna get that data when this procedure returns a ref cursor value? There are more then 5000 records in that table and i am not getting that data, but a ref cursor value. Can someone please explain how can i get that data with ref cursor value. I have no experience with Oracle.
This is the procedure definition in oracle:
CREATE OR REPLACE PROCEDURE SAD.object_hierarchy
(nAppId IN NUMBER,
nParentId IN NUMBER DEFAULT -1,
o_cRefCursor OUT SYS_REFCURSOR)
IS
BEGIN
IF NOT o_cRefCursor%ISOPEN THEN
OPEN o_cRefCursor FOR
SELECT
h.PARENT_ID, h.CHILD_ID, h.H_LEVEL,
o.OBJECT_IDENTIFIER, o.OBJECT_TYPE_ID
FROM
(
SELECT
PARENT_ID, CHILD_ID, LEVEL AS H_LEVEL
FROM OBJECT_RELATIONSHIPS
START WITH PARENT_ID = nParentId --> -1 --= 60170
CONNECT BY PRIOR CHILD_ID = PARENT_ID
) h
INNER JOIN
OBJECTS o
ON
o.OBJECT_ID = h.CHILD_ID AND
O.APPLICATION_ID = nAppId;
END IF;
END object_hierarchy;
these are the table field definitions
Column Name Data Type
OBJECT_REL_ID NUMBER (14)
PARENT_ID NUMBER (14)
CHILD_ID NUMBER (14)
OBJECT_IDENTIFIER VARCHAR2 (255 Byte)
OBJECT_TYPE_ID VARCHAR2 (5 Byte)
and this is my code which returns error:
string oradb = "Data Source=(DESCRIPTION="
+ "(ADDRESS=(PROTOCOL=TCP)(HOST=tnt33)(PORT=1521))"
+ "(CONNECT_DATA=(SERVICE_NAME=ORCL)));"
+ "User Id=xxx;Password=xxxxx;";
OracleConnection con = new OracleConnection(oradb);
try
{
con.Open();
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "SAD.object_hierarchy";
cmd.Parameters.Add("nAppId", OracleDbType.Int16).Value = 1;
OracleParameter oraP = new OracleParameter();
oraP.OracleDbType = OracleDbType.RefCursor;
oraP.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.Add(oraP);
OracleDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
}
reader.Close();
}
catch (Exception ex)
{
con.Close();
}
Can someone please help me and explain to me why is my code returning this error: "wrong number or types of arguments in call to 'OBJECT_HIERARCHY'"
Example:
string connStr = "Data Source=...";
DataSet dataset = new DataSet();
string connStr = ConfigurationManager.ConnectionStrings["OracleConn"].ToString();
using (OracleConnection objConn = new OracleConnection(connStr))
{
OracleCommand cmd = new OracleCommand();
cmd.Connection = objConn;
cmd.CommandText = "Oracle_PkrName.Stored_Proc_Name";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("Emp_id", OracleType.Int32).Value = 3; // Input id
cmd.Parameters.Add("Emp_out", OracleType.Cursor).Direction = ParameterDirection.Output;
try
{
objConn.Open();
cmd.ExecuteNonQuery();
OracleDataAdapter da = new OracleDataAdapter(cmd);
da.Fill(dataset);
}
catch (Exception ex)
{
System.Console.WriteLine("Exception: {0}", ex.ToString());
}
objConn.Close();
}
If you're going to provide the OUT, you'll need to provide nParentId as well because .NET isn't going to name those parameters when the statement is sent to the server.
cmd.Parameters.Add("nParentId", OracleDbType.Int16).Value = -1;

Categories