I have an ASP.Net application that reads data from an Access 2010 database file (.mdb).
I can easily list all tables and views in the database like this:
string sql = "select name from msysobjects where type in (1,5)";
OleDbCommand cmd = new OleDbCommand(sql,con);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dataTable); // now dataTable contains all ojbects' names I have created in access
What I would like to inquire about is the structure of the tables/views without relying on Access. I.E, using external OleDb commands.
In Oracle, I could do so by running the command
describe table_name;
describe view_name;
describe procedure_name;
but how can it be done in MS Access?
As with all relational databases there are tables of tables (reflection data). These are normally hidden, but you can Select * From msysObjects. Filtering on Type will allow you to distinguish tables from queries from forms from reports, but also allows distinguishing internal tables from mapped tables.
If you want them listed in the Navigation Pane, then right-click on the pane, select Navigation Options, and click the Show System Objects check box.
Related
The default value of SqlDataAdapter.MissingSchemaAction is MissingSchemaAction.Add, but when I specify the AddWithKey I can't understand what it really do ?
System.Data.SqlClient.SqlDataAdapter da = new System.Data.SqlClient.SqlDataAdapter();
da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
DataSet ds = new DataSet();
da.Fill(ds, "mytable");
When the use of AddWithKey can be useful ?
Documentation here says, it "adds the necessary columns and primary key information to complete the schema"
It states the primary function of AddWithKey as: "This ensures that incoming records that match existing records are updated instead of appended."
A little reverse engineering reveals the following:
When you invoke DbDataAdapter.Fill(DataSet, string) it executes the DbCommand.ExecuteReader with CommandBehavior set to SequentialAccess
If you specify MissingSchemaAction = MissingSchemaAction.AddWithKey; the CommandBehavior.KeyInfo is added to the behavior.
This causes the DbCommand.ExecuteReader invoked internally to add the following on top of your query:
SET NO_BROWSETABLE ON;
Which is documented here by Microsoft (as below)
The browse mode lets you scan the rows in your SQL Server table and
update the data in your table one row at a time. To access a SQL
Server table in your application in the browse mode, you must use one
of the following two options:
The SELECT statement that you use to access the data from your SQL
Server table must end with the keywords FOR BROWSE. When you turn on
the FOR BROWSE option to use browse mode, temporary tables are
created.
You must run the following Transact-SQL statement to turn on the
browse mode by using the NO_BROWSETABLE option:
SET NO_BROWSETABLE ON
When you turn on the NO_BROWSETABLE option, all the SELECT statements
behave as if the FOR BROWSE option is appended to the statements.
However, the NO_BROWSETABLE option does not create the temporary
tables that the FOR BROWSE option generally uses to send the results
to your application.
Well, what i've already done - is i'm able to connect to access mdb table via Microsoft.Jet.OLEDB provider, then i can get a data from table, using select query, OleDbDataAdapter and a DataSet.
Now, i'm able to connect to Postgresql via Npgsql, but what escapes me - is how am i able to get the data from access table and put it into postgresql table?
What i want to accomplish - is get a data from access mdb table and insert it into a postgresql table using "select into" query.
I don't think you'll be able to use a "SELECT INTO" query from one database to another in this instance (since the two databases are on different engines). What you will have to do is store read the data into some CLR object from the MDB and then read the CLR data into the PostgreSQL database, which is fairly trivial. It's just not possible to do it the way you want
Here are some very amateur notes that may help you. They refer to SQL Server Express, because I do not have access to postgressql. I got the connection string from linking the SQL server table to Access and checking the connection property, however, you can also look here: http://www.connectionstrings.com/postgre-sql. The two lines insert values from table1 in Access into table2 in SQL Express. In Access, the query will fail without warnings if it is not correct (Access 2010 in this case). I tried this in Visual c# 2010 Express.
//create the database connection
OleDbConnection aConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\docs\\db.mdb");
//create the command object and store the sql query
OleDbCommand aCommand = new OleDbCommand("INSERT into [ODBC;Description=TEST;DRIVER=SQL Server;SERVER=COMP\\SQLEXPRESS;Trusted_Connection=Yes;DATABASE=test].Table2 (id, atext) select id, atext from table1", aConnection);
Hey, thanks to all who have helped me, i've finally figured it out.
So, for all who will encounter the same situation - here's the solution with a correct connection string for Postgresql.:
//create the database connection
OleDbConnection aConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\docs\\db.mdb");
//create the command object and store the sql query
OleDbCommand aCommand = new OleDbCommand("INSERT into [ODBC;DSN=PostgreSQL;DATABASE=postgres;SERVER=localhost;PORT=5432;UID=postgres;PWD=test;].Table2 (id, atext) select id, atext from table1", aConnection);
We have an application that creates a number of Visual Foxpro (DBF) tables. Each of those tables have a different schema, but they all contain a known date field.
I've been asked to create another application (in C#) that will copy the last week's worth of data from each table to a new table (in a different folder to the source tables). The distinct tables will remain (e.g. if there are three source tables, there will be three destination tables).
Over time the tables may change (e.g. new fields added), so I can't make assumptions about table structure (apart from the existence of the aforementioned date field).
What's the easiest/best way to take the data from one table and create a new table with the same structure?
I know how to query the tables to extract the data (e.g. fill a DataSet with the last week's records). However, I'm thinking there must be a better way of creating a new table and filling it with the results than manually parsing all the field information in the schema and using that to recreate the the destination table.
Working with FoxPro seems to be different enough from SQL Server to give me a headache at each turn, so I need some guidance on my approach.
The production machine has the VFP 9 OLEDB driver installed on it. If possible, we'd prefer not to have to install much else.
To get an exact copy of the data, table, and records, you can do via a single SQL-Select via
OleDbConnection oConn = new OleDbConnection("Provider=VFPOLEDB.1;Data Source=C:\\SomePath");
OleDbCommand oCmd = new OleDbCommand();
oCmd.Connection = oConn;
oCmd.Connection.Open();
oCmd.CommandText = "select * from SomeTable where someCondition into table YourNewTable";
oCmd.ExecuteNonQuery();
oConn.Close();
Your where clause could be almost anything, and the Into TABLE clause tells the VFP engine to create the result set AS A NEW TABLE, so no need to explicitly declare types, columns, etc, query data from one and push into another...
One issue of consideration... Verify the user access to obviously be able to create, read, write wherever you are trying to create the new table. You can even specify a fully qualified path, such as C:\SomeOtherPath\Monthly\MyTable1 if need be...
Try something like this (note written in VB.NET and converted use www.developerfusion.co.uk/tools ):
using System.Data.OleDb;
using System.IO;
static class Module1
{
public static void Main()
{
OleDbConnection oConn = new OleDbConnection("Provider=VFPOLEDB.1;Data Source=C:\\");
OleDbCommand oCmd = new OleDbCommand();
{
oCmd.Connection = oConn;
oCmd.Connection.Open();
// Create a sample FoxPro table
oCmd.CommandText = "CREATE TABLE Table1 (FldOne c(10))";
oCmd.CommandType = CommandType.Text;
oCmd.ExecuteNonQuery();
}
oConn.Close();
oConn.Dispose();
oCmd.Dispose();
}
}
You can simply do a:
select * from myTable into table newTable [database dbName]
as DRapp showed. However you may want to get indexes as well (if any) (BTW creating indexes via VFPOLEDB is not supported directly but you can do so using ExecScript() function). Then the easiest would be to copy the table's DBF, CDX (and FPT) files. VFP is file based.
I have a customer that has a SQL database on a hosted server; call the db "myDatabase".
The hosting co. has locked down object explorer - I can't see myDatabase in the database listed (I see tempdb and master). However, if I "use myDatabase" and then "select * from myTable", all works fine.
Since we have no access to object explorer, I can't right click and generate scripts. I thought that I might be able to use SMO to accomplish what I want, but when I attempt something similar to this:
Server myServer = new Server(conn);
Database myDB = server.Databases["myDatabase"];
Table myTbl = myDB.Tables["myTable"];
It fails - myDB is null (when I iterate through the databases collection, as expected, I only see master and tempdb - the db's I can see in object explorer). It obviously has to do with security - if I can't see the table in object explorer, it won't let me access it through SMO. Anyone have any ideas of a workaround or alternate method to allow me to generate a script?
Thx!
I haven't looked at the SMO code, but have you tried using the constructor on the database object? Maybe you can access it directly.
Database myDB = new Database(myServer, "myDatabase");
Is the myDb.Tables collection empty? Could it be that you are referencing it using the wrong name?
One option you could try is to use Linq2Sql to generate a model of the database. You can then use the model to create a new database that should be more or less identical to the original. Look up the DataContext.CreateDatabase method for more info.
Another option would be to list all tables using the following query:
select * from sys.tables
And then listing all columns in the tables using the following:
select * from sys.columns where object_id = (object id from the previous query)
This will give you all tables and columns defined in your database and should be enough to create the database structure. In addition you have system views for other objects defined as well.
I want to backup a table saving the copy in the same database with another name. I want to do it programatically using .NET 2.0 (preferably C#). Someone can point me what should I do?
Just send this query to the server:
SELECT * INTO [BackupTable] FROM [OriginalTable]
This will create the backup table from scratch (an error will be thrown if it already exists). For large tables be prepared for it to take a while. This should mimic datatypes, collation, and NULLness (NULL or NOT NULL), but will not copy indexes, keys, or similar constraints.
If you need help sending sql queries to the database, that's a different issue.
One way to do this would be to simply execute a normal query this way using INTO in SQL:
SELECT *
INTO NewTableName
FROM ExistingTableName
This automatically creates a new table and inserts the rows of the old one.
Another way would be to use SqlBulkCopy from the System.Data.SqlClient namespace. There is a nice CodeProject article explaining how to do this:
SQL Bulk Copy with C#.Net
Programmers usually need to transfer
production data for testing or
analyzing. The simplest way to copy
lots of data from any resources to SQL
Server is BulkCopying. .NET Framework
2.0 contains a class in ADO.NET "System.Data.SqlClient" namespace:
SqlBulkCopy. The bulk copy operation
usually has two separated phases.
In the first phase you get the source
data. The source could be various data
platforms such as Access, Excel, SQL..
You must get the source data in your
code wrapping it in a DataTable, or
any DataReader class which implements
IDataReader. After that, in the second
phase, you must connect the target SQL
Database and perform the bulk copy
operation.
The bulk copy operation in .Net is a
very fast way to copy large amount of
data somewhere to SQL Server. The
reason for that is the Bulkcopy Sql
Server mechanism. Inserting all data
row by row, one after the other is a
very time and system resources
consuming. But the bulkcopy mechanism
process all data at once. So the data
inserting becomes very fast.
The code is pretty straightforward:
// Establishing connection
SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder();
cb.DataSource = "SQLProduction";
cb.InitialCatalog = "Sales";
cb.IntegratedSecurity = true;
SqlConnection cnn = new SqlConnection(cb.ConnectionString);
// Getting source data
SqlCommand cmd = new SqlCommand("SELECT * FROM PendingOrders",cnn);
cnn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
// Initializing an SqlBulkCopy object
SqlBulkCopy sbc = new SqlBulkCopy("server=.;database=ProductionTest;" +
"Integrated Security=SSPI");
// Copying data to destination
sbc.DestinationTableName = "Temp";
sbc.WriteToServer(rdr);
// Closing connection and the others
sbc.Close();
rdr.Close();
cnn.Close();
You could use the SQL Server Management Objects (SMO). You could make a copy of a database (data and schema). There are a lot of options you can set. The following example copies the entire database:
// Connect to the server
Server server = new Server(".");
// Get the database to copy
Database db = server.Databases["MyDatabase"];
// Set options
Transfer transfer = new Transfer(db);
transfer.CopyAllObjects = true;
transfer.DropDestinationObjectsFirst = true;
transfer.CopySchema = true;
transfer.CopyData = true;
transfer.DestinationServer = ".";
transfer.DestinationDatabase = "MyBackupDatabase";
transfer.Options.IncludeIfNotExists = true;
// Transfer Schema and Data
transfer.TransferData();
You can find the documentation of the Transfer Class on MSDN.
Depending on how many records in the table this could be a very bad idea to do from C# and the user interface.
For a small table
use the following SQL
Create table table2 (field1 int, field2 varchar(10)) --use the actual field names and datatypes of course)
insert into table2 (field1, field2)
select field1, field2 from table1
I suggest the create table to create it once and then the insert so that you can add records to the table multiple times. Select into only will work once.
At the very least, you could do "SELECT * INTO NEWTable FROM OldTable".
Do you want to create all the indexes/constraints etc?
EDIT: Adding to splattne's comments, you will have to get the handle to Table instance of the table you wish to copy. Use the Script method to get the script it will generate. Modify the script string to replace old names with new names & run it on the DB.
EDIT2: http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.table.table.aspx
http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.tableviewtabletypebase.script.aspx