Issue:
After running an Sql command with SqlCommand() on a database that then inserts data into another database, all following statements error with ExceptionInvalid object name.
Question:
Why is this happening?
Additional Information:
I know how to fix it by adding The Temp database name before the table on the select portion but since it is being run in the context of that database that shouldn't be necessary and is not when I run the statements individually in SQL management studio
Program Logic:
Create and fill temp database (All tables ASI_...)
In context of temp database select data and then insert it into another database (#AcuDB)
Repeat Step 2 for X queries
Insertion code:
if (TempD.State == System.Data.ConnectionState.Closed) TempD.Open();
Command = new SqlCommand(temp, TempD);
Command.CommandTimeout = 0;
Command.ExecuteNonQuery();
Sample Sql being run that errors after previous similar statement:
insert into #AcuDB..Batch (CompanyID,BranchID,
Module,BatchNbr,CreditTotal,DebitTotal,ControlTotal,CuryCreditTotal,CuryDebitTotal,CuryControlTotal,CuryInfoID,LedgerID,BatchType,Status,AutoReverse,AutoReverseCopy,OrigModule,OrigBatchNbr,DateEntered,Released,Posted,LineCntr,CuryID,ScheduleID,NoteID,CreatedByID,CreatedByScreenID,CreatedDateTime,LastModifiedByID,LastModifiedByScreenID,LastModifiedDateTime,Hold,Description,Scheduled,Voided,FinPeriodID,TranPeriodID)
select 2,
1,Module,BatchNbr,CreditTotal,DebitTotal,ControlTotal,CuryCreditTotal,CuryDebitTotal,CuryControlTotal,i.CuryInfoID,
isnull((select a.LedgerID from #AcuDB..ledger a where a.LedgerCD =
b.LedgerID),0)
[LedgerID],BatchType,Status,AutoReverse,AutoReverseCopy,OrigModule,OrigBatchNbr,
DateEntered
[DateEntered],Released,Posted,LineCntr,b.CuryID,ScheduleID,NoteID,
'B5344897-037E-4D58-B5C3-1BDFD0F47BF9' [CreatedByID], '00000000'
[CreatedByScreenID], GETDATE() [CreatedDateTime],
'B5344897-037E-4D58-B5C3-1BDFD0F47BF9' [LastModifiedByID], '00000000'
[LastModifiedByScreenID], GETDATE()
[LastModifiedDateTime],Hold,Description,Scheduled,Voided,b.FinPeriodID,TranPeriodID
from Temp..ASI_GLBatch b inner join #AcuDB..CurrencyInfo i on
i.CuryEffDate = b.DateEntered cross join #AcuDB..glsetup g where
b.companyID = #CpnyCD and b.branchID = #BranchCD
Going across databases like this is always precarious due to the way SQL will try to imply contexts. In this case, unless #AcuDB contains the fully-qualified address that includes both the database and the schema, you're going to get errors because of the way you're switching contexts around. Get a reading on what #AcuDB contains and try to run the batch in a stored procedure. Set up a separate instance to sandbox the scenario if you have to. The C# end of this is going to continue to complicate things until you cut it out for a little bit and make sure your SQL is good. After you're sure it's okay, integrate it back into the C# code and work from there.
Related
I have 4-5 tables in one database (not SQL Server).
In my UI, users can enter some SQL conditions together with column names in a textbox. I need to verify if the SQL is correct and if these columns exist, and show any errors accordingly. I am using C# for server side.
I have a SQL Server database where our UI stores all the UI related information.
One approach is to create all these tables (just the table structure) in my SQL Server as well and then query a simple select on each table and show the errors or success message(s) accordingly.
So basically I would have the where clause as below or more conditions:
where a = b and c in(1,2)
As mentioned above I would execute the above where clause against each table I created in SQL Server which would return error if column does not exist.
Is there a better way to approach this? I was thinking in case there is some other way to work without creating so many tables on my SQL Server.
I don't want to hard code these as the structure might change in near future. So looking for some maintainable solution. May be create a single table and store all this information in it.
Any suggestions are appreciated.
In SQL server you can query the system object :
information_schema.columns.
That contains a list of all columns for all tables and views.
However, I agree with previous comments - the design you describe is bad bad bad.
Ignoring the SQL injection troubles for a second, if the users have control over only the WHERE clause of the query, then you could try and run something like
select top 0 * from <tables> where <user-entered-where-clause>
and then gracefully handle any errors that are returned.
use dmv function in MS sql server to validate the query string.
assign user string to the variable #Str_query
declare #Str_query as nvarchar(max);
set #Str_query ='SELECT [role_code],[role_description] FROM [dbname].[dbo].[Roles]'
SELECT error_message FROM sys.dm_exec_describe_first_result_set(#Str_query, NULL, 0) WHERE column_ordinal = 0
if there is an error message then query string is not valid for execution.
I am building an application in which I will producing some reports based off the results of some SQL queries executed against a number of different databases and servers. Since I am unable to create stored procedures on each server, I have my SQL scripts saved locally, load them into my C# application and execute them against each server using ADO.NET. All of the SQL scripts are selects that return tables, however, some of them are more complicated than others and involve multiple selects into table variables that get joined on, like the super basic example below.
My question is, using ADO.NET, is it possible to assign a string of multiple SQL queries that ultimately only returns a single data table to a SqlCommand object - e.g. the two SELECT statements below comprising my complete script? Or would I have to create a transaction and execute each individual query separately as its own command?
-- First Select
SELECT *
INTO #temp
FROM Table1;
--Second Select
SELECT *
FROM Table1
JOIN #temp
ON Table1.Id = #temp.Id;
Additionally, some of my scripts have comments embedded in them like the rudimentary example above - would these need to be removed or are they effectively ignored within the string? This seems to be working with single queries, in other words the "--This is a comment" is effectively ignored.
private void button1_Click(object sender, EventArgs e)
{
string ConnectionString = "Server=server1;Database=test1;Trusted_Connection=True";
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
SqlCommand cmd = new SqlCommand("--This is a comment \n SELECT TOP 10 * FROM dbo.Tablw1;");
DataTable dt = new DataTable();
SqlDataAdapter sqlAdapt = new SqlDataAdapter(cmd.CommandText.ToString(), conn);
sqlAdapt.Fill(dt);
MessageBox.Show(dt.Rows.Count.ToString());
}
}
Yes, that is absolutely fine. Comments are ignored. It should work fine. The only thing to watch is the scopin of temporary tables - if you are used to working with stored procedures, the scope is temporary (they are removed when the stored procedure ends); with direct commands: it isn't - they are connection-specific but survive between multiple operations. If that is a problem, take a look at "table variables".
Note: technically this is up to the backend provider; assuming you are using a standard database engine, you'll be OK. If you are using something exotic, then it might be a genuine question. For example, it might not work on "Bob's homemade OneNote ADO.NET provider".
Yes, you can positively do it.
You can play with different types of collections, or with string Builder for passing queries even you can put the string variable and assign the query to it.
While the loop is running put in temp table or CTE, its totally depends on you to choose the approach. and add the data to datatable.
So if you want the entire data to be inserted or Updated or deleted then you can go for transaction,it won't be any issue.
I don't use ado.net, I use Entity Framework but I think this is more a SQL question than an ADO.NET question; Forgive me if I'm wrong. Provided you are selecting from Table1 in both queries I think you should use this query instead.
select *
from Table1 tbl1
join Table1 tbl2
on tbl1.id = tbl2.id
Actually I really don't ever see a reason you would have to move things into temp tables with options like Common Table Expressions available to you.
look up CTEs if you don't already know about them
https://www.simple-talk.com/sql/t-sql-programming/sql-server-cte-basics/
I am trying to call a stored procedure from another stored procedure.
I tried different syntax but with no success.
The first stored procedure returns a table. For the test, I just want to return from the second stored procedure what I got from the first one.
First stored procedure (SP01):
BEGIN
DECLARE C2 CURSOR WITH RETURN FOR
SELECT DISTINCT TBL.*
FROM LIB.TABLE1 TBL;
OPEN C2 ;
END
It works fine when calling it from c#.
Second stored procedure (SP02):
BEGIN
DECLARE C2 CURSOR WITH RETURN FOR
CALL SP01();
OPEN C2 ;
END
I am getting an error:
Vendor Code: -104
Message: [SQL0104] Token SP01 was not valid. Valid tokens: ;. Cause ....
A syntax error was detected at token SP01.
What is the correct syntax / approach for SP02?
EDITED:
In ms access, I was able to create a query QUERY2 based on another query QUERY1:
SELECT * FROM QUERY1;
or even joining it like a table
SELECT * FROM TABLE1 INNER JOIN QUERY1 ON (TABLE1.FIELD1 = QUERY1.FIELD1);
I need to move all my tables and queries from mdb to AS400 and write a C# application that use those queries.
I do not see so much examples on the net, maybe my approach is wrong.
I have multiple queries to run and each one depends on another one. I thought calling one stored procedure from my C# application and this one will call to another one and so on.
Is it a correct way to run a series of queries that depends one to each other?
Or is there a way to call from my c# application to all the queries independently and from the code to build the dependency between them, look like this approach is wrong?
If you are using IBM i version 6.1 or earlier, you cannot access result sets returned by a stored procedure using a language SQL stored procedure. For version 7.1 or later, you can use the ASSOCIATE RESULT SET LOCATORS statement to retrieve the result sets. See the ASSOCIATE LOCATORS statement in the SQL Reference manual (http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_71/db2/rbafzassocloc.htm?lang=en) for more information.
Once you have the locator, you use the ALLOCATE CURSOR statement (http://www-01.ibm.com/support/knowledgecenter/ssw_ibm_i_72/db2/rbafzalloccsr.htm?lang=en) to get a cursor from the RESULT SET LOCATOR.
Further examples can be found here: http://www.itjungle.com/fhg/fhg082510-printer02.html
In C# I want to execute a query that use 2 different databases (One is Access for local, and other is distant and is MySQL)
I'm able to do it in VBA Access, but how I can make the same thing in C# ??
This is how I made it in Access:
Link my 2 differents table/databases in Table
In VBA:
sSQL = "INSERT INTO DB1tblClient SELECT * FROM DB2tblClient"
CurrentDb.Execute sSQL
How I can execute this SQL in C# ? (What object to use, etc... Example code if you can)
Thanks !
There are two ways to do this. One is to set up linked tables on Access and run a single query. The other is to run both queries from c# and join them with linq.
The first way is better. If you really have to do it with linq, here is some sample code:
dWConnection.Open();
dWDataAdaptor.SelectCommand = dWCommand1;
dWDataAdaptor.Fill(queryResults1);
dWDataAdaptor.SelectCommand = dWCommand2;
dWDataAdaptor.Fill(queryResults2);
dWConnection.Close();
IEnumerable<DataRow> results1 = (from events in queryResults1.AsEnumerable()
where events.Field<string>("event_code").ToString() == "A01"
|| events.Field<string>("event_code").ToString() == "ST"
select events ) as IEnumerable<DataRow>;
var results2 = from events1 in queryResults1.AsEnumerable()
join events2 in queryResults2.AsEnumerable()
on (string)events1["event_code"] equals (string)events2["event_code"]
select new
{
f1 = (string)events1["event_code"],
f2 = (string)events2["event_name"]
};
DataTable newDataTable = new DataTable();
newDataTable = results1.CopyToDataTable<DataRow>();
See why I said linked tables is better?
You should be able to run the same SQL command from any app, really. This is assuming:
You're connecting to Access from your C# app
DB1tblClient is a local Access table
DB2tblClient is a link table in Access
Given these, you might try the following:
using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Stuff\MyAccessdb.mdb"))
{
conn.Open();
using (OleDbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO DB1tblClient SELECT * FROM DB2tblClient";
cmd.ExecuteNonQuery();
}
}
You might want to check connectionstrings.com if you can't get the connection string right, and you may need to install some components (MDAC or ACE) for connections that use those providers.
Well it is not possible to run this such complex query with single statement.
Basically each query execution object initialized by particular database information,
so need two different object for each database first think.
Now 2 Object need with initialized with its own connection object.
Just fetch data by first object and insert it to another database by usin second connection object.
You need to keep following points in mind before trying this type of query
Both the databases are accessible from your code.
There is inter-connectivity between both the database.
Both the databases are available for the user that you are using to execute this query.
You need to specify the query in following format
DATABASE_NAME.SCHEMA_NAME.TABLE_NAME instead of just TABLE_NAME
EDIT
If you don't have inter-connectivity between databases you can follow following steps
Connect to Source database using one connection.
Read the data from source database into a dataset or datatable using SELECT query.
Connect to target database using a second connection.
Insert all the records one by one using a loop to TARGET Database using standard INSERT query
I'm stuck on a little problem concerning database.
Once a month I get a XML file with customer information (Name, address, city,etc.). My primary key is a customer number which is provided in the XML file.
I have no trouble inserting the information in the database;
var cmd = new SqlCommand("insert into [customer_info]
(customer_nr, firstname, lastname, address_1, address_2, address_3.......)");
//some code
cmd.ExecuteNonQuery();
Now, I would like to update my table or just fill it with new information. How can I achieve this?
I've tried using TableAdapter but it does not work.
And I'm only permitted to add one XML because I can only have one customer_nr as primary key.
So basically how do I update or fill my table with new information?
Thanks.
One way would be to bulk insert the data into a new staging table in the database (you could use SqlBulkCopy for this for optimal insert speed). Once it's in there, you could then index the customer_nr field and then run 2 statements:
-- UPDATE existing customers
UPDATE ci
SET ci.firstname = s.firstname,
ci.lastname = s.lastname,
... etc
FROM StagingTable s
INNER JOIN Customer_Info ci ON s.customer_nr = ci.customer_nr
-- INSERT new customers
INSERT Customer_Info (customer_nr, firstname, lastname, ....)
SELECT s.customer_nr, s.firstname, s.lastname, ....
FROM StagingTable s
LEFT JOIN Customer_Info ci ON s.customer_nr = ci.customer_nr
WHERE ci.customer_nr IS NULL
Finally, drop your staging table.
Alternatively, instead of the 2 statements, you could just use the MERGE statement if you are using SQL Server 2008 or later, which allows you to do INSERTs and UPDATEs via a single statement.
If I understand your question correctly - if the customer already exists you want to update their information, and if they don't already exist you want to insert a new row.
I have a lot of problems with hard-coded SQL commands in your code, so I would firstly be very tempted to refactor what you have done. However, to achieve what you want, you will need to execute a SELECT on the primary key, if it returns any results you should execute an UPDATE else you should execute an INSERT.
It would be best to do this in something like a Stored Procedure - you can pass the information to the stored procedure at then it can make a decision on whether to UPDATE or INSERT - this would also reduce the overhead of making several calls for your code to the database (A stored procedure would be much quicker)
AdaTheDev has indeed given the good suggestion.
But in case, you must insert/update from .NET code then you can
Create a stored procedure that will handle insert/update i.e. instead of using a direct insert query as command text, you make a call to stored proc. The SP will check if row exists or not and then update (or insert).
User TableAdapter - but this would be tedious. First you have to setup both insert & update commands. Then you have to query the database to get the existing customer numbers and then update the corresponding rows in the datatable making the Rowstate as Updated. I would rather not go this way.