I have a SQLite database contains several tables which some of them (not all) have a specific column called 'attachment'. I wonder if there is a query that get values of the 'attachment' column from all the tables which have this column. I can get all tables' name from the database, and then, query all tables individually. But I think there must be a single query to do this.
You can use SQLite code to get the sql SELECT statement as a string and execute it to get all the values of the column attachment in all tables of the database:
SELECT GROUP_CONCAT('SELECT ' || pti.name || ' FROM ' || sm.name, ' UNION ALL ') sql
FROM sqlite_master sm CROSS JOIN pragma_table_info(sm.name) pti
WHERE sm.type = 'table' AND pti.name = 'attachment';
The above query returns a resultset with only 1 row and 1 column aliased as sql with a value of a string like this:
SELECT attachment FROM table1
UNION ALL
SELECT attachment FROM table2
UNION ALL
SELECT attachment FROM table4
You can change UNION ALL to UNION inside the function GROUP_CONCAT(), depending on your requirement.
See a simplified demo.
You can get the values of every attachment field in every table that has this field defined using the GetSchema method on the connection to find all the relevant tables then you can use the sql stament UNION to extract in a single command all the attachments values.
This should be the code using only standard ADO.NET commands and methods:
using(SQLiteConnection cnn = new SQLiteConnection(#"Data Source=E:\\temp\\mydb.db;Version=3"))
{
cnn.Open();
// We want all columns with the name as "attachment"
DataTable dt = cnn.GetSchema("COLUMNS", new string[] {null, null, null, "attachment"});
// Now we prepare the single commands that extract the attachments value
// from every row returned by the previous query.
// The TABLE_NAME field contains the name of the relevant table
var s = dt.AsEnumerable().Select(x => $"SELECT attachment FROM [{x.Field<string>("TABLE_NAME")}]");
// We join together the single commands separating them with the UNION statement
string command = string.Join(" UNION ", s);
// Finally we can construct and execute a command loading a datatable
// with all the attachements values from every table.
SQLiteCommand cmd = new SQLiteCommand(command, cnn);
dt = new DataTable();
dt.Load(cmd.ExecuteReader());
// Here you can work on the single field in the _dt_ table
....
}
Note, UNION will extract a distinct value for each attachment. This means that if you have two attachments with the same name, it will be listed only one time. If you want to keep everything then change UNION to UNION ALL (with spaces before and after the statement)
Related
I have this code in C#, but I need it to select all columns EXCEPT the first column of the table (the identity column), so that when I insert the data into an identical table in a different database, the destination database assigns its own identity column values:
SqlCommand commandSourceData = new SqlCommand($"SELECT * FROM dbo.{tableName};", sourceConnection);
SqlDataReader reader = commandSourceData.ExecuteReader();
Is there a way to do this?
If you want a generic solution for every column in your database you can use this kind of code
public string GetColumnsWithoutIdentity(string tableName, SqlConnection con)
{
SqlDataAdapter da = new SqlDataAdapter($"SELECT * FROM dbo.{tableName} where 1=0", con);
DataTable dt = new DataTable();
da.FillSchema(dt, SchemaType.Source);
var cols = dt.Columns.Cast<DataColumn>().Where(x => !x.AutoIncrement).Select(x => x.ColumnName);
return string.Join(",", cols);
}
Now you can use the returned string to build an Sql statement without the autoincrement column.
Notice that this code is vulnerable to Sql Injection. You should be absolutely sure that the tableName parameter used to build the first query is not typed directly by your user. Let it choose from a whitelist (readonly) of predefined tables (and also this is not 100% safe)
Another drawback is the fact that you need to hit the database two times. Once to get the schema with the info about the AutoIncrement column and one to fill the datatable after that.
I want query all the existing tables whose name begin with specific string in database using oledb GetSchema method.
In other words I am looking for equivalent of the following sql query:
SELECT * FROM information_schema.tables WHERE table_name LIKE 'customer%'
Something like:
String[] tableRestrictions = new String[4];
tableRestrictions[2] = "%customer";
DataTable customerTables = conn.GetSchema("Tables", tableRestrictions );
In this case the table name I want to query from is Dynamic. Therefore I needed to get the whole table name first.
It seems there is not efficient way to do that but using an iteration.
I came to this conclusion that using Linq provides the neatest solution(Thanks to Tim's answer to a similar case):
// Get the tables using GetSchema:
dtbTables = dbConnection.GetSchema("tables");
// use linq to get the table whose name matches the criteria:
DataRow recSpecificTable = dbConnection.GetSchema("Tables").AsEnumerable()
.Where(r => r.Field<string>("TABLE_NAME")
.StartsWith("customer")).FirstOrDefault();
// Now the table name I am looking for:
tableName = Convert.ToString(recSpecificTable["TABLE_NAME"]).Trim();
I have a performance problem with displaying data from an SQL database in my application. The problem is that I have a large number of parameters that I need to display (customers personal data, his current statistics etc.).
So far I've used either SqlCommand.ExecuteScalar (for single parameters), or DataTable.Rows[].ItemArray.GetValue() (for multiple parameters - I fill the DataTable with SqlDataAdapter whose query withdraws the necessary data from the database) and assigned their values to the appropriate control. Assuming that command is an SqlCommand type:
For single parameter
command.CommandText = "SELECT Parameter1 FROM MyTable WHERE Condition = Value";
textBox1.Text = command.ExecuteScalar().ToString();
For multiple parameters (SDA is a SqlDataAdapter):
command.CommandText="SELECT Parameter1 - ParameterN FROM MyTable WHERE Condition = Value";
SDA.SelectCommand = command;
SDA.Fill(MyDataTable);
textBox1.Text = MyDataTable.Rows[0].ItemArray.GetValue(0).ToString();
comboBox1.Text = MyDataTable.Rows[0].ItemArray.GetValue(1).ToString();
/*
I repeat similar lines of code for each parameter and display it in the appropriate control.
*/
This approach works correctly but when I have a large number of parameters (20+), it works very slowly.
Is there a more efficient way to display these amounts of data, and how would I implement it?
Thank you
Probably, with the second example, a SqlDataReader will perform better because you read the values just one time, while with a DataAdapter, you need to load the DataTable and then loop over the rows of the table (Effectively reading data two times).
command.CommandText="SELECT Field1,...,FieldN FROM MyTable WHERE Condition = Value";
SqlDataReader reader = command.ExecuteReader();
while(reader.Read())
{
// Of course this works correctly just if your query returns one row....
textBox1.Text = reader.GetString(0);
comboBox1.Text = reader.GetString(n);
}
You could also try with the Field<T> extension for the DataRow
command.CommandText="SELECT Field1,...,FieldN FROM MyTable WHERE Condition = Value";
SqlDataAdapter SDA = new SqlDataAdapter(command);
SDA.Fill(MyDataTable);
textBox1.Text = MyDataTable.Rows[0].Field<string>("Field1");
comboBox1.Text = MyDataTable.Rows[0].Field<string>("FieldN");
However, I think that the real performance gain would be in the query that you submit to the database engine and in the correct working of indexes on your tables.
Try to retrieve the minimun number of rows possible, search on indexed fields and/or change to a stored procedure.
here i had write sample stored procedure in wich you can get idea...
you can pass as amny parameter as you can in xml format and insert into temp table...
now you have table with value Name/value pair means Paramater name /value....
now you can do your furteher work...
/*
EXEC wa_TempGetDaya '<SampleXML>
<tblXML><AccountID>3</AccountID><Code>11</Code><Description>Leptospiral infect NEC</Description></tblXML>
</SampleXML>'
*/
CREATE PROCEDURE wa_TempGetDaya
(
#ParaXML NVARCHAR(MAX)
)
AS
SET NOCOUNT ON
BEGIN
DECLARE #AccountID INT
DECLARE #MyXML XML
SET #MyXML = #ParaXML
IF OBJECT_ID('tempdb..#TempData') IS NOT NULL
DROP TABLE #TempData
SELECT * INTO #TempData
FROM (
SELECT
Parse.value('(AccountID)[1]', 'INT') AS 'AccountID',
Parse.value('(Code)[1]', 'Varchar(100)') AS 'Code',
Parse.value('(Description)[1]', 'varchar(1000)') AS 'Description'
FROM
#MyXML.nodes('/SampleXML/tblXML') AS YourData(Parse)
) AS tbl
declare #para1 varchar(20)
declare #para2 varchar(20)
declare #para3 varchar(20)
SELECT #para1 =AccountID ,#para2 =Code,#para3 =Description from #TempICD
END
I need to programmatically create a SQL Server 2008 table in C# such that the columns of the table should be generated from a list of columns (each column name is the name of a row in the table)
My question is what is the command string to loop through the list of columns and creates the table's recorded:
List<string> columnsName = ["col1","col2","col3"]
I want to create a table with the columns in the columnsName. But since the list size in not constant, I need to loop through the list to generate the table columns.
The simple answer is
CREATE TABLE table_name
(
column_name1 data_type,
column_name2 data_type,
column_name3 data_type,
....
)
from w3Schools.com
In C# use a string builder to concatenate the query and then execute the query.
StringBuilder query = new StringBuilder();
query.Append("CREATE TABLE ");
query.Append(tableName);
query.Append(" ( ");
for (int i = 0; i < columnNames.Length; i++)
{
query.Append(columnNames[i]);
query.Append(" ");
query.Append(columnTypes[i]);
query.Append(", ");
}
if (columnNames.Length > 1) { query.Length -= 2; } //Remove trailing ", "
query.Append(")");
SqlCommand sqlQuery = new SqlCommand(query.ToString(), sqlConn);
SqlDataReader reader = sqlQuery.ExecuteReader();
Note: tableName, columnNames, and columnTypes would be replaced with what ever you are getting the data from. From your description it sounds like you are getting the column values from a query, so rather than using a for loop and arrays you will probably be using a while loop to iterate through the results to build the query. Let me know if you need an example using this method and I will make one tonight.
If you are having trouble with the syntax for creating the table you can try creating the table (or a sample table) in MS SQL Server Management Studio, then right click the table and select Script Table as\Create To\New Query Editor Window. This will show you the script it would use to build the query.
Are you looking to implement something like an Entity–attribute–value model?
http://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model
I have a database with two tables. Both of these tables are related and have the same key field. For example, both of them have rows of data corresponding to ISBN = 12345, but the two tables have differing data about that ISBN.
So, I'm trying to figure out how to display data from both tables into one dataGridView. I have tried some SQL commands I found online, but it looks like commands in C# might differ from normal SQL queries.
Suppose table1 has these fields: ISBN, color, size and table2 has the fields ISBN, weight.
I need a way to display ISBN, color, size, weight in my datagrid view. I think I will have to somehow do this with an adapter. I am able to connect and do queries on the tables individually, and show that data in my datagridview, but I can't figure out how to mix data from two separate tables.
If you have a good resource I can read about this I'd love to have it, my google-fu is failing me.
Here's an example of something I can do now with my database:
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'database1DataSet.Book' table. You can move, or remove it, as needed.
this.bookTableAdapter.Fill(this.database1DataSet.Book);
string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + #"C:\Users\Geoff\Documents\cs 351\Database1.accdb" + ";Persist Security Info=False;";
OleDbConnection conn = new OleDbConnection(connectionString);
string query = "select * from Book where ISBN = 12345";
OleDbCommand com = conn.CreateCommand();
com.CommandText = query;
OleDbDataAdapter adapter = new OleDbDataAdapter(com);
DataSet data = new DataSet();
conn.Open();
adapter.Fill(data);
conn.Close();
dataGridView1.DataSource = data.Tables[0];
}
So, essentially, I'd like to do what I've done above, but I want to include the data from a different table too. The other table also has a key field ISBN, and it contains values of ISBN that match the first table.
Look into the use of JOIN to return the results from two tables JOINed together ON some common value
See Also
Wikpedia: Join
(SQL)
W3Schools: SQL
Joins
SQL-tutorial.net: SQL
Join
SO: SQL JOIN ON vs WHERE
Coding Horror: visual explanation of SQL JOINs
There's nothing limiting this to C# or OLEDB -- it's basic SQL.
For the specifics of what you're asking a query might look like the following:
SELECT T1.ISBN, T1.color, T1.size, T2.weight
FROM table1 T1
INNER JOIN table2 T2
ON T1.ISBN = T2.ISBN
WHERE ISBN = '12345';
(There's no need to alias table1 as T1 -- I just did that as an example; in more complicated queries with longer table names, you might not want to repeat the table name all the time)
since ISBN occurs in both tables, it must be explicitly qualified in your field-selections; either T1 or T2 can be used, as they are identical
since color, size and weight each occur in only one table, they do NOT need to be qualified -- but it doesn't hurt.
var query = "SELECT t1.isbn, t1.color, t1.size, t2.weight FROM table1 t1 JOIN table2 t2 ON t2.isbn = t1.isbn";
var connection = new System.Data.SqlClient.SqlConnection("your SQL connection string here");
var dataAdapter = new System.Data.SqlClient.SqlDataAdapter(query, connection);
var dataSet = new System.Data.DataSet();
dataAdapter.Fill(dataSet);
yourGridView.DataSource = dataSet;
yourGridView.DataBind();
This is one of many solutions. I think the code might be faster if you create an in-memory DataTable and use an SqlDataReader, but the sample above is simpler.
When working with MSSQL databases, you normally use the System.Data.SqlClient classes. If you - for whatever reason - use OleDb, pick the corresponding objects from the System.Data.OleDb namespace.
You can query records from both tables using UNION ALL
SELECT 'In table 1', book_author, book_title, book_isbn
FROM books
WHERE book_isbn = '67890'
UNION ALL
SELECT 'In table 2', othertable_author, othertable_title, othertable_isbn
FROM othertable
WHERE othertable_isbn = '67890'
of course you'll need to manually fill the '67890' in both places using whatever method is more convenient in your situation.