I have two tables (1-N relationship).
(ID,name,surname),
(ID,Job(s),role,society).
In my app I want to merge table1 and table2 (based on the id that binds the two tables) BUT i want to hide the columns that COULD be empty.
Example: (in this case, i don't want to show 'ruolo/grado')
How I wrote the code for this:
CREATE PROCEDURE spEstraiPbyId
#Id int
as
begin
SELECT * from Persone
join Lavori on Persone.Id = #Id and Lavori.IdPersona=#Id
end
PS: I have already seen several similar questions on the internet but no answer was able to satisfy my request or I did not understand correctly. I hope you can help me willingly.
If I understand it correctly, you want to do something like this:
http://sqlfiddle.com/#!18/04141/3
SELECT * from Persone
join Lavori on Persone.Id = Lavori.IdPersona where Lavori.Job is not null
First, use the on joining the keys, and then filter with a where those that are not null :)
Thank you all. Best tip was written by #Serg because to do this i worked on client side, with DataReader and Datatable objs:
DataTable tbl = new DataTable()
SqlCommand cmd = new SqlCommand("spEstraiPById", cnn); //See at the end for spEstraiPById
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("Id",txtNickname.Text);
using (SqlDataReader rdr = cmd.ExecuteReader())
{ //Add columns to the table
tbl.Columns.Add("ID");
tbl.Columns.Add("Nome");
tbl.Columns.Add("Cognome");
tbl.Columns.Add("Residenza");
tbl.Columns.Add("Professione");
tbl.Columns.Add("Ruolo");
tbl.Columns.Add("Società");
while (rdr.Read())
{ //from DB to Table
DataRow drw = tbl.NewRow();
drw["ID"] = rdr["Id"];
drw["Nome"] = rdr["Nome"];
drw["Cognome"] = rdr["Cognome"];
drw["Residenza"] = rdr["Residenza"];
drw["Professione"] = rdr["Professione"];
drw["Ruolo"] = rdr["Ruolo/Grado"];
drw["Società"] = rdr["Società"];
tbl.Rows.Add(drw);
}
foreach (DataRow row in tbl.Rows) //Deleting empty records
{
for (int col = tbl.Columns.Count - 1; col >= 0; col--)
{
if (row.IsNull(col))
{
tbl.Columns.RemoveAt(col);
}
}
// No need to continue if we removed all the columns
if (tbl.Columns.Count == 0)
break;
}
}
gw1.DataSource = tbl;
gw1.DataBind();
cnn.Close();
//=Stored Procedure
CREATE PROCEDURE spEstraiPbyId
#Id int
as
begin
SELECT * from Persone
join Lavori on Persone.Id = #Id and Lavori.IdPersona=#Id
end
Related
Here is my code
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(Request.QueryString["id"]))
{
string clientId = Context.User.Identity.GetUserId();
if (clientId != null)
{
int id = Convert.ToInt32(Request.QueryString["id"]);
customize1 customize = new customize1
{
client_id = clientId,
product_id = id,
paper_type = Labelpt.Text,
corner = Labelpc.Text,
shipping_type = Labelsp.Text,
text = TextBox3.Text,
amount = Convert.ToInt32(lbResult.Text)
};
customizeModel model = new customizeModel();
Label9.Text = model.Insertcustomize(customize);
con.Open();
SqlCommand cmd2 = con.CreateCommand();
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "select top 1 * from customize1 where client_id='"+clientId+"' order by Id desc ";
cmd2.ExecuteNonQuery();
DataTable dt2 = new DataTable();
SqlDataAdapter da2 = new SqlDataAdapter(cmd2);
da2.Fill(dt2);
foreach (DataRow dr2 in dt2.Rows)
{
customizeid = dr2["Id"].ToString();
}
con.Close();
}
}
}
I need the last row id but my query does not generate any value.I also check my query in SSMS and query is working fine but in asp it is not generating any data and for inserting record i used the concept of class and entity relationship.
Any Solution.
Brother there are two ways:
One is when you insert your row place after the Insert query this:
SELECT SCOPE_IDENTITY()
For example:
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
SELECT SCOPE_IDENTITY()
It gives the inserted ID back.
The second way is this query;
SELECT id FROM table ORDER BY id DESC LIMIT 1
If you keep struggling with problems be open to ask more.
Summary:
C# SqlDataReader can return table in most cases but failed in only one unit test case. However, for same test, directly running the stored procedure in Microsoft SQL Server 2016 returns table with value.
Detail:
The code input #measures is a DataTable type. In most cases, the code can return table with data or empty table correctly. However, when I set #measures to a DataTable with value 14 (14 is ID for one measure/fact and procedure should return one column of type int) , the datareader will return no row and not even the schema of the table.
I tried other valid ID (measures) by which procedure returns other int column. They all work.
using (this._connection = new SqlConnection(this._connectionString))
{
SqlCommand command = new SqlCommand();
command.Connection = this._connection;
command.CommandText = "rpt_procedure";
command.CommandTimeout = this._config.ConfTimeOutSetting;
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#measures", SqlDbType.Structured).Value = measures;
command.Parameters.Add("#parameter2", SqlDbType.Structured).Value = parameter2;
command.Parameters.Add("#Dates", SqlDbType.Structured).Value = Datetable;
command.Parameters.AddWithValue("#Gra", gra);
this._connection.OpenWithRetry(this.RetryPolicy);
using (SqlDataReader reader = command.ExecuteReader())
{
this.NumRow = 0;
DataTable schemaTable = reader.GetSchemaTable();
string[] colName = new string[colNum];
int startPoint = 0;
if (schemaTable == null)
MessageBox.Show("cannot get schema of table");
else
{
foreach (DataRow myField in schemaTable.Rows)
{
if (startPoint >= colNum)
break;
List<string> temp = new List<string>();
//For each property of the field...
colName[startPoint] = myField[schemaTable.Columns[0]].ToString();
startPoint++;
}
arrayList.Add(colName);
}
if (!reader.HasRows)
return arrayList;
while (reader.Read())
{
this.NumRow++;
string[] r = new string[colNum];
for (int i = 0; i < colNum; i++)
{
r[i] = reader[i].ToString();
}
arrayList.Add(r);
}
return arrayList;
}
}
SQL test code that returns value
declare #Measures tvpBigInt
insert into #Measures
select 14
declare #parameter2 tvpBigInt
insert into #parameter2
select 22
union
select 10
declare #Grain NVARCHAR(20)
select #Grain = 'Daily'
declare #Dates tvpDate
insert into #Dates
select '2016-12-30','2017-02-06'
exec rpt_procedure
#Measures = #Measures
#parameter2 = #parameter2
,#Gra = 'Daily'
,#Dates = #Dates
Action I took according to previous StackOverflow questions:
Tried dataadapter
Tried executenonquery cmd.ExecuteNonQuery();
Both did not work.
I have a form which use two tables to insert the data.
Some column in the form would be like:
scholarship name, course, year
Two tables that are involved are:
scholarshipDetail , scholarshipCourse.
scholarshipDetail table has scholarshipName and year
scholarshipCourse table has scholarshipID, course
scholarshipDetail:
schid schName year
-----------------------------
1 star 2015
2 moon 2016
scholarshipCourse:
schID course
------------------
1 maths
1 english
2 maths
Assuming that the new user wants to add new scholarship which means the id will 3 and it insert into two tables. How do I that? (MANAGED TO INSERT ALR)
NEW ERROR:
EDITED
public DataTable test(string name, string course)
{
string insertsql = "INSERT INTO Table1(schName) OUTPUT INSERTED.addID values (#schName)";
SqlCommand cmd = new SqlCommand(insertsql,conn);
cmd.Parameters.AddWithValue("#schName", name);
conn.Open();
int i = cmd.ExecuteNonQuery();
var table1Id = (int)cmd.ExecuteScalar();
string insertsql1 = "INSERT INTO Table2(ScholarshipID, DiplomaCourse) VALUES (#id, #course)";
SqlCommand cmd2 = new SqlCommand(insertsql1, conn);
cmd2.Parameters.AddWithValue("#id", table1Id);
cmd2.Parameters.AddWithValue("#course", course);
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = cmd;
da.SelectCommand = cmd2;
DataTable dt = new DataTable();
da.Fill(dt);
return dt;
}
The output in my table is
Table1
schID schname
-------------------
1 jj
2 jj
Table2
TableID schID Course
------------------------------
1 2 Maths
the data is being inserted twice in Table1. why is that so? (SOLVED)
Edited:
Now the problem is, there will be checkboxes which allow the user to choose which course is applicable for the scholarship.
When the user click all checkbox, only the last checkbox will insert into database.
In my codebehind(cs):
protected void Button1_Click(object sender, EventArgs e)
{
// addScholarship[] test = new addScholarship[1];
string course = "";
string Name = schName.Text;
if (DIT.Checked )
{
course = "DIT";
}
if (DFI.Checked)
{
course = "DFI";
}
addScholarship[] insertName = new addScholarship[1];
addScholarship insertedName = new addScholarship(Name,course);
scholarshipBLL obj = new scholarshipBLL();
DataTable dt = obj.test(Name, course);
}
For the latest problem you posted.
You are calling obj.test method only once after all the if blocks.
So the "course" variable will have value from the latest if block where the condition is true.
You need to call DataTable dt = obj.test(Name, course); method in every if block. That means if checkbox is checked you call insert row. If not checked then you don't insert the row.
Following is the code you should put in your button_click.
string course = "";
string Name = schName.Text;
scholarshipBLL obj = new scholarshipBLL();
List<addScholarship> addScholarshipList= new List<addScholarship>();
addScholarship scholarship;
if (DIT.Checked )
{
scholarship = new addScholarship(Name,course);
addScholarshipList.Add(insertedName);
course = "DIT";
DataTable dt = obj.test(Name, course);
}
if (DFI.Checked)
{
scholarship = new addScholarship(Name,course);
addScholarshipList.Add(insertedName);
course = "DFI";
DataTable dt = obj.test(Name, course);
}
You are executing the command twice.
int i = cmd.ExecuteNonQuery();
var table1Id = (int)cmd.ExecuteScalar();
You need to execute only one. I think removing cmd.ExecuteNoteQuery would solve your issue.
BEGIN;
INSERT INTO scholarshipDetail(schid,schName,year) VALUES(3,'sun',2017);
INSERT INTO scholarshipCourse(schID,course) VALUES(LAST_INSERT_ID(),'science');
COMMIT;
I think I have a weird doubt!!
I have created a table using C#[with a tool not programatically ] in mdb file, then I am inserting the values to that table, what the issue is I don't know how many columns are available in that table, but I wanna insert value from the datagridview..
Spire.DataExport.Access.AccessExport accessExport = new Spire.DataExport.Access.AccessExport();
accessExport.DataSource = Spire.DataExport.Common.ExportSource.DataTable;
accessExport.DataTable = this.dataGridView2.DataSource as System.Data.DataTable;
accessExport.DatabaseName = saveFileDialog1.FileName;
accessExport.TableName = "ExtractedTable";
accessExport.SaveToFile();
//OleDbCommand cmdt = new OleDbCommand("Create Table "+profiletablegrid. ", con);
string strDirectory = saveFileDialog1.FileName;
OleDbConnection conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strDirectory);
conn.Open();
for (int i = 41; i < dataGridView2.Rows.Count; i++)
{
for (int j = 0; j < dataGridView2.Rows[i].Cells.Count; j++)
{
OleDbCommand cmdd = new OleDbCommand("Insert into sample values(#a,#b,#c,#d)", conn);
cmdd.Parameters.Add("#a", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.Parameters.Add("#b", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.Parameters.Add("#c", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.Parameters.Add("#d", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.ExecuteNonQuery();
}
}
So Since I know the columns I am inserting 4 values, but if I don't know how many columns are there, then how can i insert the value...
I can count the datagridview total columns, but how can I insert according to that?
Without knowing column Names or Number of Columns of a table in my experience it's not possible to insert data in to it. How ever you can use this work around to get column names of particular table then insert data into those columns.
The first thing you would do is make sure that no data gets returned:
SELECT TOP 0 your_table.* FROM your_table WHERE 1 = 2;
Now assuming you know how to set up a DataReader you would do the following:
using(var reader = command.ExecuteReader())
{
// This will return false - we don't care, we just want to make sure the schema table is there.
reader.Read();
var table = reader.GetSchemaTable();
foreach (DataColumn column in table.Columns)
{
Console.WriteLine(column.ColumnName);
}
}
Now you have column names so build up your insert statement.
Ok Consider you have n number of columns then your code will look like this.
List<string> colArr=new List<string>();
foreach (DataColumn column in table.Columns)
{
colArr.Add(column.ColumnName);
}
now build your sql in this way.
string colNames="";
string val="";
for (int i = 0; i < colArr.Count; i++)
{
if(i!=colArr.Count-1)
{
colNames+=col+",";
val+="Some Value,";
}
else
{
colNames+=col;
val+="Some Value";
}
}
string sqlQuery="Insert Into your_Table "+colNames+" ("+val+")";
assuming you are using OleDbConnection you can call
DataTable schema = connection.GetSchema("Columns");
to get the schema data of your Database ... in that table you will find each column of each table in the db ...
use that to build you SQL statement at runtime
I have to perform a bulk operation bool AddEntitiesX(List<X>):
For each insert of X into X_Table (with X_UID as auto-increment ID), I have to insert k-times another entity Y into Y_Table (with X_UID as FK and Y_UID as auto-increment ID), since X contains a list of k-Y entities.
Then, for each inserted X, I need to insert also a Z entity in Z_Table (with X_UID as FK and Z_UID as auto-increment ID).
My pseudo-code will look like this:
// cannot use 'TransactionScope' since there are problems with Oracle
// so, prepare SqlTransaction
foreach (X)
{
//1. call 'InsertX' SP
foreach (Y in x.ListY)
//2. call 'InsertY' SP
//3. call 'InsertZ' SP
}
// commit transaction
How can I retrieve the X_UID from InsertX SP to pass to the next stored procs?
If there is no way, then since I cannot have this big transaction in one stored procedure, how should I model it?
I would like to know best practices to handle this kind of operations from business to data layer using transactions.
Thank you... and please let me know if my question is not clear enough.
One way is to use SCOPE_IDENTITY(), like cdel already suggested. Another way is to use the OUTPUT clause of INSERT
INSERT INTO table (field, field, ...)
OUTPUT INSERTED.ID
VALUES (#value, #value, ...);
This inserts the record and also produces a result set, which contains the inserted row generated identity value. In C# you read this result set just as if you'd have executed a SELECT, ie. you use ExecuteReader().
One advantage of using OUTPUT clause is that is the only way it can reliable return multiple row IDs. Say you insert not one, but 100, you can get back the IDs of all 100 inserted rows in a single result set. In case you wonder how to insert 100 rows in one swoop, see Arrays and Lists in SQL Server 2008: Using Table-Valued Parameters.
Another advantage of using OUTPUT clause is that you can chain two statements into a single one, see Chained Updates.
You can use Bulk Copy. Using this, first bulk insert all the records of x in a new table and bulk insert all records of Y in a new table.
Now you can use Cross joins in between these two new tables..like below
Select X.TableXVal, Y.TableYVal from NewTableX X
Cross Join NewTableY Y
This query can be written in the Stored Procedure and stored procedure can be called like below
using (System.Data.SqlClient.SqlConnection con = new SqlConnection("YourConnection string")) {
con.Open();
SqlCommand cmd = new SqlCommand();
string expression = "Parameter value";
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Your Stored Procedure";
cmd.Parameters.Add("Your Parameter Name",
SqlDbType.VarChar).Value = expression;
cmd.Connection = con;
using (IDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
{
}
}
}
You can create the sample tables like below
create table NewTableX
(
ID int Primary Identity(1,1),
TableXVal int
)
create table NewTableY
(
ID int Primary Identity(1,1),
TableYVal int
)
In this way, you can skip inserting the records one by one. hope this will help you.
For more information about using BulkCopy. Below is the code.
private void CreateDataTableFromList()
{
//supose you have list for X like below
List<int> x = new List<int>();
x.Add(1);
x.Add(2);
x.Add(3);
x.Add(4);
//supose you have list for Y like below
List<int> y = new List<int>();
y.Add(1);
y.Add(2);
y.Add(3);
y.Add(4);
DataTable dt = new DataTable();
DataColumn dc;
DataRow dr;
dc = new DataColumn();
dc.DataType = System.Type.GetType("System.Int32");
dc.ColumnName = "TableXVal";
dt.Columns.Add(dc);
dr = dt.NewRow();
dr["TableXVal"] = 1;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TableXVal"] = 2;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TableXVal"] = 3;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TableXVal"] = 4;
dt.Rows.Add(dr);
SqlBulkCopy copy = new SqlBulkCopy("Your Connection String");
copy.DestinationTableName = "NewTableX";
copy.WriteToServer(dt);
dt = new DataTable();
dc = new DataColumn();
dc.DataType = System.Type.GetType("System.Int32");
dc.ColumnName = "TableYVal";
dt.Columns.Add(dc);
dr = dt.NewRow();
dr["TableYVal"] = 1;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TableYVal"] = 2;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TableYVal"] = 3;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["TableYVal"] = 4;
dt.Rows.Add(dr);
copy = new SqlBulkCopy("Your Connection String");
copy.DestinationTableName = "NewTableY";
copy.WriteToServer(dt);
}
Step1 - Use CreateDataTableFromList function
Step 2 - Call stored procedure as mentioned above
Your stored procedure must have the select statement as mentioned above.
Have your InsertX sp structured like this:
ALTER PROCEDURE dbo.InsertX
(
-- other parameters
#ID int = null OUTPUT,
#ErrMsg nvarchar(512) = null OUTPUT
)
AS
SET NOCOUNT ON
DECLARE #ret as int
SET #ret = 1
BEGIN TRY
INSERT INTO [dbo].[XTable]
([Column1])
VALUES
(null)
SET #ID = SCOPE_IDENTITY()
SET #ErrMsg = 'OK'
END TRY
BEGIN CATCH
SET #ErrMsg = ERROR_MESSAGE()
SET #ret = -1
END CATCH
RETURN #ret
After the call you get the ID and feed it into InsertY