Sql Server temporary table disappears - c#

I'm creating a temporary table, #ua_temp, which is a subset of regular table. I don't get an error, but when I try to SELECT from #ua_temp in the second step, it's not found. If I remove the #, a table named ua_temp is created.
I've used the exact same technique from created the table with SELECT INTO elsewhere. It runs fine, so I don't think it has anything to do with database settings. Can anyone see the problem?
// Create temporary table
q = new StringBuilder(200);
q.Append("select policy_no, name, amt_due, due_date, hic, grp, eff_dt, lis_prem, lis_grp, lis_co_pay_lvl, ");
q.Append("lep_prem, lapsed, dn_code, [filename], created_dt, created_by ");
q.Append("into #ua_temp from elig_ua_response ");
q.Append("where [filename] = #fn1 or [filename] = #fn2 ");
sc = new SqlCommand(q.ToString(), db);
sc.Parameters.Add(new SqlParameter("#fn1", sFn));
sc.Parameters.Add(new SqlParameter("#fn2", sFn2));
int r = sc.ExecuteNonQuery();
MessageBox.Show(r.ToString() + " rows");
// Rosters
q = new StringBuilder(200);
q.Append("select policy_no,name,amt_due,due_date,hic,grp,eff_dt,");
q.Append("lis_prem,lis_grp,lis_co_pay_lvl,lep_prem,lapsed,dn_code,[filename] ");
q.Append("from #ua_temp where (lis_prem > 0.00 or lep_prem > 0.00) ");
q.Append("and [filename] = #fn order by name");
sc.CommandText = q.ToString();
sc.Parameters.Clear();
sc.Parameters.Add(new SqlParameter("#fn", sFn));
sda = new SqlDataAdapter(sc);
sda.Fill(ds, "LIS LEP Roster");
To answer some of the obvious questions: This program was running fine using the source table, elig_ua_response. The reason for introducing the temp table was that I want to delete some of the rows for this particular report. I put brackets around the column [filename] while testing to be sure it's not a key word issue. The second SELECT works fine if you replace #ua_temp with elig_ua_response. I've tried different names for the temp table. The MessageBox showing the number of rows was just for debugging purposes; it doesn't affect the problem.

Joe Zack's comment is what helped me understand what's happening here. A very clear and concise explanation. This should be an answer so that it's more visible to people arriving here from a google search.
SqlCommand calls sql with parameters via sp_executesql when there are parameters, which means your temp table gets created inside (and then clean up in) a stored procedure so it's not available to future calls - even when they share the same connection

I think the solution to your problem is to combine the creation of the temp table and selecting from that temp table into one query (see code snippet #3 below). Executing the command twice (as you do in the code in your question) seems to work ok if you are not using command parameters, but fails if they are introduced. I tested a few different approaches and here's what I found.
1) WORKS OK: Use same command object, no command parameters, execute command twice:
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
const string query = #"
CREATE TABLE #temp
([ID] INT NOT NULL, [Name] VARCHAR(20) NOT NULL)
INSERT INTO #temp VALUES(1, 'User 1')
INSERT INTO #temp VALUES(2, 'User 2')";
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT * FROM #temp";
using (var sda = new SqlDataAdapter(cmd))
{
var ds = new DataSet();
sda.Fill(ds);
foreach (DataRow row in ds.Tables[0].Rows)
Console.WriteLine("{0} - {1}", row["ID"], row["Name"]);
}
}
}
2) FAILS: Use same command object, command parameters, execute command twice:
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
const string query = #"
CREATE TABLE #temp
([ID] INT NOT NULL, [Name] VARCHAR(20) NOT NULL)
INSERT INTO #temp VALUES(1, #username1)
INSERT INTO #temp VALUES(2, #username2)
";
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
cmd.Parameters.Add("#username1", SqlDbType.VarChar).Value ="First User";
cmd.Parameters.Add("#username2", SqlDbType.VarChar).Value ="Second User";
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = "SELECT * FROM #temp";
using(var sda = new SqlDataAdapter(cmd))
{
var ds = new DataSet();
sda.Fill(ds);
foreach(DataRow row in ds.Tables[0].Rows)
Console.WriteLine("{0} - {1}", row["ID"], row["Name"]);
}
}
}
3) WORKS OK: Use same command object, command parameters, execute command once only:
using (var conn = new SqlConnection("..."))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
const string query = #"
CREATE TABLE #temp
([ID] INT NOT NULL, [Name] VARCHAR(20) NOT NULL)
INSERT INTO #temp VALUES(1, #username1)
INSERT INTO #temp VALUES(2, #username2)
SELECT * FROM #temp
";
cmd.CommandType = CommandType.Text;
cmd.CommandText = query;
cmd.Parameters.Add("#username1", SqlDbType.VarChar).Value ="First User";
cmd.Parameters.Add("#username2", SqlDbType.VarChar).Value ="Second User";
using (var sda = new SqlDataAdapter(cmd))
{
var ds = new DataSet();
sda.Fill(ds);
foreach (DataRow row in ds.Tables[0].Rows)
Console.WriteLine("{0} - {1}", row["ID"], row["Name"]);
}
}
}

This works. Apparently, if the SqlParameters are in the step that creates the table, the table is not left behind for the next step. Once the table is created, the SqlParameters can be used in a separate step for the INSERT.
// Create temporary file dropping members from termed groups.
q = new StringBuilder(500);
q.Append("create table #ua_param ");
q.Append("([ID] int not null, fn varchar(50) not null) ");
sc = new SqlCommand(q.ToString(), db);
sc.ExecuteNonQuery();
q = new StringBuilder(500);
q.Append("insert into #ua_param values(1,#fn1) ");
q.Append("insert into #ua_param values(2,#fn2) ");
sc = new SqlCommand(q.ToString(), db);
sc.Parameters.Add(new SqlParameter("#fn1", sFn));
sc.Parameters.Add(new SqlParameter("#fn2", sFn2));
sc.ExecuteNonQuery();
q = new StringBuilder(500);
q.Append("select policy_no, name, amt_due, due_date, hic, grp, eff_dt, lis_prem, lis_grp, lis_co_pay_lvl, ");
q.Append("lep_prem, lapsed, dn_code, [filename], created_dt, created_by ");
q.Append("into #ua_temp from elig_ua_response inner join #ua_param on [filename] = fn ");
sc.Parameters.Clear();
sc.CommandText = q.ToString();
sc.CommandTimeout = 1800;
sc.ExecuteNonQuery();

Its because the temp table is just that. Temporary. You might consider doing your operations in a stored procedure.

Beyond rolling it into a stored procedure as suggested by #Daniel A White, you can look at BOL article and search for global temporary tables. Also a brief write up on Temporary Tables. Either approach should keep the temporary table alive.

I had the same problem. I tried the SeaDrive solution and it works, however my tests make me believe that the query execution "flushes" something between "ADO.NET/SQLDriver" and the MS SQL Server.
So, you need to isolate the "CREATE TABLE" statement and submit it to the database before to use it with "INSERT INTO". Composed commands joining CREATE and INSERT in one unique statement doesn't work, unless you can give up the parameters.

#TEMP tables only are accessible within the same session or SPID. So if you want to reuse it you need to reuse the connection you used to generate it.

Working example with Dapper:
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
var expected = Guid.NewGuid();
// creating the temp table with NO PARAMETERS PASSED IN is the key part.
conn.Execute("CREATE TABLE #MyTemp (ID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY);");
// now that the temp table is created, you can run queries with params as
// much as you want.
conn.Execute("INSERT INTO #MyTemp (ID) VALUES (#ID)", new { ID = expected });
var actual = conn.Query<Guid>("SELECT ID FROM #MyTemp;").Single();
Assert.Equal(expected, actual); // proof it worked
}

Using a stored proc makes sense for this sort of thing.
If for some reason that's not feasible, then make sure you are using the same connection for the temp table creation as you are for the temp table selection, else the temp table won't be visible. (it might be that you have this issue randomly if you're using connection pooling.) Alternately, use a real, physical table or even a global temp table (##global_tmp vs #local_tmp), but in either case you'll need to devise a scheme/protocol such that multiple processes aren't trying to create/delete/write to that table.
Again, I'll stress that a stored proc would be a good route, if possible.

Related

How to get output parameter and also a table when executing a stored procedure

Scenario
I'm working with SQL Server 2017 (not possible to change)
I'm using Visual Studio 2019 in C# console and .NET Framework 4.5 (possible to change)
I'm using ADO.NET because several years before we couldn't use Entity Framework, as the system is made to work with a stored procedure that returns at least 100k rows (possible to change)
Situation
I have an USP that returns a table that is at least 100k of rows by 20 fields. I need to add an output parameter in order to get also an ID created by the USP itself. So, the situation is that I need return a table and an ID (called ProcMonitorId). I don't know if this is even so possible (See workarounds section)
At the SQL level is seems to be so far so good:
CREATE PROCEDURE [myschema].[mystore]
#ProcMonitorId BIGINT OUTPUT
AS
BEGIN
BEGIN TRANSACTION
(...)
SELECT fields FROM myTable
SELECT #ProcMonitorId = #internalVariable
SQL execution:
And at repository layer (only relevant lines, someone were surprised for health of example):
var command = new SqlCommand("myStoreProcedure", mycon);
command.CommandType = CommandType.StoredProcedure;
SqlParameter outPutParameter = new SqlParameter();
outPutParameter.ParameterName = "#ProcMonitorId";
outPutParameter.SqlDbType = System.Data.SqlDbType.BigInt;
outPutParameter.Direction = System.Data.ParameterDirection.Output;
command.Parameters.Add(outPutParameter);
// Open connection etc-etc that works
SqlDataAdapter da = new SqlDataAdapter(command);
DataTable dt = new DataTable();
string ProcMonitorId = outPutParameter.Value.ToString();
da.Fill(dt);
Everything worked fine until the addition of the output at C# level. It returns in the line:
string ProcMonitorId = outPutParameter.Value.ToString();
it returns NullReferenceException because Value is null (that can't be) and of course, can't convert to String. I would solve this situation by adding a ? but if that's situation happens for real, I need catch it any way as error. The main idea is that Value can not be null.
As I don't have any ORM map, (and my expertise is not ADO.NET but Entity Framework) I can't understand why is null (No, is not null at SQL layer, always return a value)
Question
How can I solve this error or how can I return a BIGINT parameter and ALSO a table result?
Workarounds
As I first glance I have to solve it quickly, I made a:
SELECT 1 as type, #procID as procid, null as data1, null as data2
UNION ALL
SELECT 2 as type, null as procid, data1, data2
in order to simulate a "header" and "data" rows on one single table.
But I don't like this solution and is not very elegant and flexible. I've to parse the header every time.
Thanks in advance and please comment anything, tip, help, workaround, I will be glade to update my answer if more information is needed.
Also I can make my Framework to .NET Core or change to Entity Framework. That I can't change is my SQL version
Update #2
No changes in SQL - Still working as screenshot
In C# - Hangs out for ever
SqlConnection connection = new SqlConnection(ConfigurationManager.AppSettings["DbConnection"]);
connection.Open();
var command = new SqlCommand("myUSP", connection);
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = Convert.ToInt16(ConfigurationManager.AppSettings["DataBaseTimeOut"]);
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
SqlParameter r = command.Parameters.Add("#ProcMonitorId", SqlDbType.BigInt);
r.Direction = ParameterDirection.Output;
DataTable dt = new DataTable();
using (var rdr = command.ExecuteReader())
{
dt.Load(rdr);
long id = (long)r.Value;
}
SqlDataAdapter da = new SqlDataAdapter(command);
da.Fill(dt);
The parameter value won't be available until after you consume the resultset, eg
var cmd0 = new SqlCommand("create or alter procedure pFoo #id int output as begin select * from sys.objects; set #id = 12; end", con);
cmd0.ExecuteNonQuery();
var cmd = new SqlCommand("pFoo", con);
cmd.CommandType = CommandType.StoredProcedure;
var p1 = cmd.Parameters.Add("#id", SqlDbType.Int);
p1.Direction = ParameterDirection.Output;
var dt = new DataTable();
using (var rdr = cmd.ExecuteReader())
{
dt.Load(rdr);
var id = (int)p1.Value;
}
You should use a Parameter with the Direction property set to ReturnValue, and, inside the sp, declare an internal variable and set it to the value you want.
Then call the RETURN statement before leaving the StoredProcedure.
As an example, see this SP:
ALTER PROCEDURE [GetTimeZoneGMT]
#TimeZone NVARCHAR(128)
AS
BEGIN
DECLARE #timeZoneNumber as INT = -20;
IF #TimeZone ='Pacific/Midway'
SET #timeZoneNumber = -11
ELSE IF #TimeZone ='Pacific/Niue'
SET #timeZoneNumber = -11
ELSE IF #TimeZone ='Pacific/Pago_Pago'
SET #timeZoneNumber = -11
SELECT 1 -- or whatever you need to have as result set
RETURN #timeZoneNumber;
END
The stored procedure ends with a (bogus) SELECT statement but also has a RETURN statement with the parameter set inside the SP logic.
Now from the C# side you could call it in this way (LinqPad example)
using (var connection = new SqlConnection("Data Source=(LOCAL);Initial Catalog=LinqPADTest;Integrated Security=True;"))
{
connection.Open();
SqlCommand cmd = new SqlCommand("GetTimeZoneGMT", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#TimeZone", SqlDbType.NVarChar).Value = "Asia/Kuala_Lumpur";
SqlParameter r = cmd.Parameters.Add("#p2", SqlDbType.BigInt);
r.Direction = ParameterDirection.ReturnValue;
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
r.Value.Dump(); // Prints -20
dt.Dump(); // Prints a row with a single column with 1 as value
}

Returning data table from Oracle stored procedure that has input parameters to a .NET application

I have done some research into my issue, but I think I am struggling because of my lack of experience with Oracle (coming exclusively from a SQL Server background).
I'm trying to call an Oracle stored procedure from a .NET application and to return a data table to my application. I'm getting an "ORA-00900: invalid SQL statement" error.
Pseudocode-behind:
OracleConnection conn = new OracleConnection("...");
OracleCommand cmd = new OracleCommand("sproc_name", conn);
cmd.Connection = conn;
cmd.Parameters.Add("Year", OracleDbType.Int16).Value = vYear
cmd.Parameters.Add("Name", OracleDbType.Varchar2).Value = vName;
cmd.Parameters.Add("ID", OracleDbType.Varchar2).Value = vID;
conn.Open();
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
Pseudo stored procedure:
CREATE OR REPLACE
PROCEDURE sproc_name
(
Year IN NUMBER
, Name IN VARCHAR2
, ID IN VARCHAR2
)
AS
BEGIN
SELECT *
FROM TABLE
WHERE TABLE.Year = Year AND
TABLE.Name = Name AND
TABLE.ID = ID
END sproc_name;
I have read up on reference cursors and I tried to rewrite my procedure with no luck. How should I proceed here?
Try this
using (var conn = new OracleConnection("..."))
using (var cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sproc_name";
cmd.BindByName = true;
//...
Replying a bit old question, but its always good to reply an answered question,
Oracle never give you output as sql. For getting result set you need to identify sys_refcursor as Out parameter.
So, your procedure will be looks like
Also try to name proper (just a suggestion) :)
CREATE OR REPLACE PROCEDURE sproc_name (
numYear IN NUMBER
, strName IN VARCHAR2
, numID IN VARCHAR2,
, cr_output out sys_refcursor
)
AS
BEGIN
open cr_output for
SELECT *
FROM TABLE
WHERE TABLE.Year = Year AND
TABLE.Name = Name AND
TABLE.ID = ID
END sproc_name;

MS Access - C# - Retrieve the latest inserted guid

Is there a way to retrieve the latest inserted guid in access with C#?
I tried this: Created a table Cars with a field Id of type autonumber, replicationID and a field Name varchar(250).
var command = myConnection.CreateCommand();
command.Connection.Open();
command.CommandText = "INSERT INTO Cars(Name) VALUES ('Pagani')";
command.ExecuteNonQuery();
command = context.Database.Connection.CreateCommand();
command.CommandText = "SELECT ##Identity";
Console.WriteLine(command.ExecuteScalar());
command.Connection.Close();
The issue which I am getting is:
Console.WriteLine(command.ExecuteScalar());
always shows 0
EDIT
To create the table you can use this statement over the C# OleDb connection (I think that from MS Access query does not work)
CREATE TABLE [Cars] (
[Id] guid not null DEFAULT GenGUID(),
[Name] text null
);
ALTER TABLE [Cars] ADD CONSTRAINT [PK_Cars_6515ede4] PRIMARY KEY ([Id])
I know this is not exactly what you are asking for, but let me suggest an alternative solution which might solve your underlying problem.
Create the GUID in C# and pass it to your insert:
var newGuid = Guid.NewGuid();
var command = myConnection.CreateCommand();
command.Connection.Open();
command.CommandText = "INSERT INTO Cars(Id, Name) VALUES (?, 'Pagani')";
command.Parameters.AddWithValue("#Id", newGuid); // Note: OleDb ignores the parameter name.
command.ExecuteNonQuery();
Console.WriteLine(newGuid);
GUIDs are unique. It really doesn't matter whether it is generated by your application or by the Access database driver.
This option is in all respects superior to reading the GUID afterwards:
You only need one database access.
It's less code.
It's easier.
And you can still omit the GUID in your INSERT in cases where you don't need to know the GUID - no need to change existing code.
If SELECT ##IDENTITY does not work for "ReplicationID" AutoNumber fields then the most likely way to retrieve such a value for a new record is to use an Access DAO Recordset insert, like this:
// required COM reference:
// Microsoft Office 14.0 Access Database Engine Object Library
var dbe = new Microsoft.Office.Interop.Access.Dao.DBEngine();
Microsoft.Office.Interop.Access.Dao.Database db = dbe.OpenDatabase(
#"C:\Users\Public\Database1.accdb");
Microsoft.Office.Interop.Access.Dao.Recordset rst = db.OpenRecordset(
"SELECT [Id], [Name] FROM [Cars] WHERE FALSE",
Microsoft.Office.Interop.Access.Dao.RecordsetTypeEnum.dbOpenDynaset);
rst.AddNew();
// new records are immediately assigned an AutoNumber value ...
string newReplId = rst.Fields["Id"].Value; // ... so retrieve it
// the returned string is of the form
// {guid {1D741E80-6847-4CB2-9D96-35F460AEFB19}}
// so remove the leading and trailing decorators
newReplId = newReplId.Substring(7, newReplId.Length - 9);
// add other field values as needed
rst.Fields["Name"].Value = "Pagani";
// commit the new record
rst.Update();
db.Close();
Console.WriteLine("New record added with [Id] = {0}", newReplId);
which produces
New record added with [Id] = 1D741E80-6847-4CB2-9D96-35F460AEFB19
You can try like this using the OUTPUT :
INSERT INTO myTable(myGUID)
OUTPUT INSERTED.myGUID
VALUES(GenGUID())
You can try like this:
string str1 = "INSERT INTO Cars(Name) VALUES ('Pagani')";
string str2 = "Select ##Identity";
int ID;
using (OleDbConnection conn = new OleDbConnection(connect))
{
using (OleDbCommand cmd = new OleDbCommand(str1, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
cmd.CommandText = str2;
ID = (int)cmd.ExecuteScalar();
}
}

How to do faster insert query in c#?

I would like to insert all the id's in a sql table. The following way works but this take very long. What is the best or better way to do this to increase the speed.
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
string query = "";
foreach (var id in ids) // count = 60000
{
{
query += "INSERT INTO [table] (id) VALUES (" + id + ");";
}
}
SqlCommand command = new SqlCommand(query, connection);
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
reader.Close();
}
connection.Close();
}
You can use the SqlBulkCopy to insert large amounts of data - something like this:
// define a DataTable with the columns of your target table
DataTable tblToInsert = new DataTable();
tblToInsert.Columns.Add(new DataColumn("SomeValue", typeof (int)));
// insert your data into that DataTable
for (int index = 0; index < 60000; index++)
{
DataRow row = tblToInsert.NewRow();
row["SomeValue"] = index;
tblToInsert.Rows.Add(row);
}
// set up your SQL connection
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
// define your SqlBulkCopy
SqlBulkCopy bulkCopy = new SqlBulkCopy(connection);
// give it the name of the destination table WHICH MUST EXIST!
bulkCopy.DestinationTableName = "BulkTestTable";
// measure time needed
Stopwatch sw = new Stopwatch();
sw.Start();
// open connection, bulk insert, close connection
connection.Open();
bulkCopy.WriteToServer(tblToInsert);
connection.Close();
// stop time measurement
sw.Stop();
long milliseconds = sw.ElapsedMilliseconds;
}
On my system (PC, 32GB RAM, SQL Server 2014) I get those 60'000 rows inserted in 135 - 185 milliseconds.
Consider Table-Valued Parameters. They are an easy way to send a batch of data into a stored procedure that will then handle them on the SQL side, and they aren't restricted in most of the other approaches you will see are (insert limits, etc).
In the database create a custom Type that has the schema of your table.
CREATE TYPE dbo.TableType AS TABLE
( ID int )
Create a DataTable that matches your table schema (including column name and order).
DataTable newTableRecords = new DataTable();
// Insert your records, etc.
Create a stored procedure that receives a table parameter, and inserts the records from that parameter into your real table.
CREATE PROCEDURE usp_InsertTableRecords
(#tvpNewTableRecords dbo.TableType READONLY)
AS
BEGIN
INSERT INTO dbo.Table(ID)
SELECT tvp.ID FROM #tvpNewTableRecords AS tvp;
END
Call the procedure from your application code, passing in your data table as a parameter.
using (connection)
{
// Configure the SqlCommand and SqlParameter.
SqlCommand insertCommand = new SqlCommand(
"usp_InsertTableRecords", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue(
"#tvpNewTableRecords", newTableRecords);
tvpParam.SqlDbType = SqlDbType.Structured;
// Execute the command.
insertCommand.ExecuteNonQuery();
}
I've had really great performance at very large volumes with this approach, and it is nice because it allows everything to be set-based without any arbitrary insert limits like the INSERT INTO (Table) VALUES (1),(2),(3)... approach.

Select Into Explanation / Temporary Tables

Based on the tutorial on SQL Temporary Tables, it should be OK to create a temp table by using SELECT * INTO #tempTable FROM tableA but it's throwing me SQLException when I trying to SELECT * FROM #tempTable saying that Invalid object name '#tempTable'. May I know what's the proper way of using a temp table in C#?
string sql = "SELECT * INTO ##tempTable FROM (SELECT * FROM tableA)";
using (var command = new SqlCommand(sql, connection))
{
string sqlNew = "SELECT * FROM ##tempTable";
using (var command2 = new SqlCommand(sqlNew, connection))
{
using (var reader = command2.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader["column1"].ToString());
}
Console.ReadLine();
}
}
}
My Objective is tryint to using the data retrieved from sqlVar and insert them into a tempTable and perform some operation on it. Very much appreciated if there is some sample code on how to fit the code into the above code. Thank You.
But why you need temp table at SQL server side..
1) if you wish to perform operation on C# side just take data in DATASET instead of DATAREADER .. and
DataSet dataset = new DataSet();
using (SqlConnection conn = new SqlConnection(connString))
{
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand("select * from tableA", conn);
conn.Open();
adapter.Fill(dataset);
conn.Close();
foreach (DataRow row in dataset.Tables[0]) // Loop over the rows.
{
// perform your operation
}
}
2) if you need to perform operation on SQL side then create a stored procedure at SQL server .. in the stored procedure create #table and use it ..
3) and you do not want to create DATASET then you can take data LIST and perform your operation on C# side
You are not executing the first command at all, so the SELECT INTO isn't executed, so the temporary table is not created, so you get an error about the table not existing.
The code should read:
string sql = "SELECT * INTO ##tempTable FROM (SELECT * FROM tableA)";
using (var command = new SqlCommand(sql, connection))
{
command.ExecuteNonQuery(); // <-- THIS
string sqlNew = "SELECT * FROM ##tempTable";
using (var command2 = new SqlCommand(sqlNew, connection))
{
using (var reader = command2.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader["column1"].ToString());
}
Console.ReadLine();
}
}
}
1-SELECT * INTO # tempTable FROM tableA (local temp)or
2-SELECT * INTO ## tempTable FROM tableA (global temp)then
Local temp tables are only available to the current connection for the user; and they are automatically deleted when the user disconnects from instances. Local temporary table name is stared with hash ("#") sign.
Global Temp Table
Global Temporary tables name starts with a double hash ("##"). Once this table has been created by a connection, like a permanent table it is then available to any user by any connection. It can only be deleted once all connections have been closed.
Both, Temporary tables are stored inside the Temporary Folder of tempdb. Whenever we create a temporary table, it goes to Temporary folder of tempdb database.
temp table in SQL DB
Change your temp table from #tempTable to ##tempTable.
Using ## means a global temp table that stays around. You'll need to Drop it after you have completed your task.
If Exists(Select * from tempdb..sysobjects Where id = object_id('tempdb.dbo.#tempTable'))
DROP TABLE #tempTable
I think your answer is in the comment:
Temporary tables available during the session that creates them.
If you want to actualy get the data you have to perform a SELECT statement from this temporary table within the same scope.
One more thing:
I don't see you are executing the var command, you are missing this line:
string sql = "SELECT * INTO ##tempTable FROM (SELECT * FROM tableA)";
using (var command = new SqlCommand(sql, connection))
{
command.ExecuteNonQuery();// This line is missing..
string sqlNew = "SELECT * FROM ##tempTable";
using (var command2 = new SqlCommand(sqlNew, connection))
{
using (var reader = command2.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader["column1"].ToString());
}
Console.ReadLine();
}
}
}
But missing the line isn't the reason why your implementation is wrong..

Categories

Resources