SQLite data dictionary tables and columns - sqlite

Can you tell us the names of all tables and table columns in the SQLite data dictionary?
Update:
I was using this information for a Basic4Android app I'm developing.
Here is the actual segment of coding I used:
' Create the PeopleToVisit table which holds lookup data about each visit.
'-------------------------------------------------------------------------
If SQL.ExecQuerySingleResult( _
"SELECT count(name) FROM sqlite_master WHERE type='table' AND name='PeopleToVisit'") _
= 0 Then
ToastMessageShow("Creating the People to Visit table.", False)
' Create it now since it doesn't yet exist.
'------------------------------------------
SQL.ExecNonQuery("CREATE TABLE PeopleToVisit (" & _
"Id INTEGER PRIMARY KEY, " & _
"FirstName TEXT, " & _
"LastName TEXT, " & _
"Address1 TEXT, " & _
"Address2 TEXT, " & _
"City TEXT, " & _
"State TEXT, " & _
"Zip TEXT " & _
")")
End If
' New table columns for Version 1.2
'----------------------------------
' Coding for when new data columns need to be added to the database table.
'-------------------------------------------------------------------------
strCreateTableStatement = _
SQL.ExecQuerySingleResult("SELECT sql " & _
"FROM sqlite_master " & _
"WHERE Type = 'table' AND name = 'PeopleToVisit'")
' Check if the new columns are in the table.
'-------------------------------------------
If strCreateTableStatement.IndexOf("PrimaryPhone TEXT") = -1 Then
' We need to add the new columns to the table.
'---------------------------------------------
SQL.ExecNonQuery("ALTER TABLE PeopleToVisit ADD COLUMN PrimaryPhone TEXT")
SQL.ExecNonQuery("ALTER TABLE PeopleToVisit ADD COLUMN SecondaryPhone TEXT")
SQL.ExecNonQuery("ALTER TABLE PeopleToVisit ADD COLUMN Email TEXT")
SQL.ExecNonQuery("ALTER TABLE PeopleToVisit ADD COLUMN LastVisitNote TEXT")
End If

To list all tables in a database
SELECT name FROM sqlite_master WHERE type='table'
To list all columns in a table
pragma table_info(table_name)

Related

Make Certificate Visible to user after user meets target

I am having problem wrapping my head around this problem.
If you run the query embedded in code below, it shows Total Questions (TotalQuestions) asked, Total Correct (TotalCorrect2) and percentage correct (PercentCorrect2).
We have students who participate in video tutorials.
After each lesson, they are given quizzes, a total of 30 questions.
To pass through each segment of the tutorials, a student must score at least 80% of the quizzes.
The code below is calculating Total questions, total correct and percentage correct.
Here is where I am having issues.
If a student answers all 30 questions AND gets 80% or more of the questions correct, a certificate is exposed to the student so s/he can print his or her certificate.
If both criteria is not met, the certificate stays hidden from the student.
I am having difficulty with the IF portion of this task.
For instance,
if totalQuestions = 30 and percentCorrect2 >= 80 then
btnGetUser.Visible = True
else
btnGetUser.Visible = False
end if
This above is not working.
When I run the code, and a particular user meets the condition of the IF statement, the certificate is supposed to be exposed. It does so when I run it in SSMS.
So far, the certificate has remained hidden even though I am testing with users who have taken and passed the tests and have made the conditions.
When I debug the code, I can see that totalQuestions shows 30 which is correct but the rest show 0.
Any ideas what I could be doing wrong?
Dim s As String = ";WITH Questions AS " & _
" ( SELECT SQ.QuestionID, " & _
" CorrectChoices = COUNT(NULLIF(SC.IsCorrect, 0)), " & _
" ChoicesGiven = COUNT(SA.ChoiceID), " & _
" CorrectChoicesGiven = COUNT(CASE WHEN SA.ChoiceID IS NOT NULL AND SC.IsCorrect = 1 THEN 1 END), " & _
" ExtraChoicesGiven = CASE WHEN COUNT(SA.ChoiceID) > COUNT(NULLIF(SC.IsCorrect, 0)) THEN COUNT(SA.ChoiceID) - COUNT(NULLIF(SC.IsCorrect, 0)) ELSE 0 END " & _
" FROM SurveyQuestions SQ " & _
" INNER JOIN SurveyChoices SC " & _
" ON SQ.QuestionId = SC.QuestionID " & _
" LEFT JOIN SurveyAnswers SA " & _
" ON SA.QuestionId = SC.QuestionID " & _
" AND SA.ChoiceID = SC.ChoiceID " & _
" AND SA.UserName = #username " & _
" GROUP BY SQ.QuestionID " & _
" ), QuestionScores AS " & _
" (SELECT QuestionID, " & _
" Score = CASE WHEN CorrectChoicesGiven - ExtraChoicesGiven < 0 THEN 0 " & _
" ELSE CAST(CorrectChoicesGiven - ExtraChoicesGiven AS FLOAT) / CorrectChoices " & _
" END, " & _
" Score2 = ISNULL(CAST(CorrectChoicesGiven AS FLOAT) / NULLIF(CASE WHEN ChoicesGiven > CorrectChoices THEN ChoicesGiven ELSE CorrectChoices END, 0), 0) " & _
" FROM Questions " & _
" )
" SELECT TotalQuestions = COUNT(*), " & _
" TotalCorrect = SUM(Score), " & _
" PercentCorrect = CAST(100.0 * SUM(Score) / COUNT(*) AS DECIMAL(5, 2)), " & _
" TotalCorrect2 = SUM(Score2), " & _
" PercentCorrect2 = CAST(100.0 * SUM(Score2) / COUNT(*) AS DECIMAL(5, 2)) " & _
" FROM QuestionScores;"
Dim connStr As String = ConfigurationManager.ConnectionStrings("DBConnectionString").ConnectionString
Dim conn As New SqlConnection(connStr)
Dim cmd As New SqlCommand(s, conn)
Dim TotalQuestions As Integer
Dim TotalCorrect As Double
Dim TotalPercent As Decimal
Dim TotalCorrect2 As Double
Dim TotalPercent2 As Decimal
conn.Open()
cmd.Parameters.AddWithValue("#username", username.Text)
Dim reader As SqlDataReader = cmd.ExecuteReader()
If reader.Read() Then
TotalQuestions = reader.GetInt32(0)
TotalCorrect = reader.GetDouble(1)
TotalPercent = reader.GetDecimal(2)
TotalCorrect2 = reader.GetDouble(3)
TotalPercent2 = reader.GetDecimal(4)
End If
reader.Close()
conn.Close()
If TotalQuestions = 30 and TotalPercent2 >= 80 Then
btnGetUser.Visible = True
Else
btnGetUser.Visible = False
End If

Join Query in string format

Hi i'm trying to join tables together when loading my session variable Below is my code
Dim cmdstring As String = "SELECT * FROM Users.Location_Code = Location.Location_Code =
Medical_Equipment.Location_Code WHERE Staff_No = #StaffNo"
I am attempting a 3 table join this data will then be presented on a grid view. Is it possible for a join to be made here in this string?
Yes it is possible. But you need to have proper SQL JOIN syntax. Your current SQL query doesn't make sense. It should look about like this (I assume that Staff_No is a column in Users table) :
Dim cmdstring As String = _
"SELECT * FROM Users u " & _
"INNER JOIN Location l on l.Location_Code = u.Location_Code " & _
"INNER JOIN Medical_Equipment m on m.Location_Code = u.Location.Location_Code " & _
"WHERE u.Staff_No = #StaffNo"

Get results from two tables - asp.net/SQL Server 2008R2

I have a search form with 2 fields(first name and last name) from one table (Just has person's information) and 4 (Incident number, date, place, created by) from the other (has one or more incidents for the person in the first table) linked through foreign key(nameID). I think the problem is what kind of join to use and how to use the WHERE clause.
Thanks.
More information:
#Tim - Isn't the user input into one or more fields the filter or it is the WHERE Clause? The user doesn't have to fill in all the fields. Thats where I am getting lost. The user is trying to find the incident to update it. Does this help?
Also I have to use "Like%LName%" in the Where clause to get all the names if they don't enter the entire name.
My query looks like this:
Protected Sub BtnSearch_Click(sender As Object, e As EventArgs) Handles BtnSearch.Click
Dim strSearch As String
strSearch = "SELECT tblPatron.LName, tblPatron.FName, tblIncident.CreatedBy, "
strSearch = strSearch + "tblIncident.Inci_ID, tblIncident.Inci_date, tblIncident.Inci_type, tblIncident.Library, "
strSearch = strSearch + "tblIncident.PatronName, tblIncident.Location "
strSearch = strSearch + "FROM tblPatron INNER JOIN tblIncident ON tblPatron.PatronID = tblIncident.PatronID "
strSearch = strSearch + "WHERE "
strSearch = strSearch + "(tblPatron.LName Like '%" + txtLName.Text.ToString() + "%') "
strSearch = strSearch + "AND (tblPatron.FNAME Like '%" + txtFName.Text.ToString() + "%')"
strSearch = strSearch + "AND (tblIncident.Inci_ID ='" + strInciNum.Text.ToString() + "')"
strSearch = strSearch + "AND (tblIncident.Inci_date = '" + txtInciDate.Text.ToString() + "')"
strSearch = strSearch + "AND (tblIncident.Inci_type = '" + ddInciCat.SelectedValue.Trim + "')"
strSearch = strSearch + "AND (tblIncident.Library = '" + ddLib.SelectedValue.Trim + "')"
SearchPDS.SelectCommand = strSearch
SearchPDS.DataBind()
GridSearchResults.DataBind()
GridSearchResults.Visible = True
End Sub
do this:
SELECT A.FirstName, A.LastName, B.IncidentNumber, B.Date, B.Place, B.CreatedBy
FROM Name A INNER JOIN Incident B
ON A.NameID = B.NameID
SELECT firstname, lastname, incidentnumber, date, place, createdby
FROM name n
INNER JOIN incident i ON n.nameID = i.nameID
WHERE firstname LIKE '%'+#firstname+'%'
AND lastname LIKE '%'+#lastname+'%'
Where #firstname and #lastname are parameters containing values from the search fields
In your string concatenation style, just add txtFName.Text.ToString() and txtLName.Text.ToString() into the string in place of those parameters.
I took the suggestion of logixologist. On the click event I added multiple if statements to check for the null value and then add build the query string. At the same time I made one of the dropdown to be a default value instead of "Select" and that would be my starting Where parameter. This works for me now. There might be a better way of writing the query, I am just beginner with asp.net
Thanks for all your replies. I love this forum.
What you need is dynamic sql. Basically you start by declaring a varchar(max)
DECLARE #Sql as varchar(max)
Then you will set it to the base SQL Statement:
SET #SQL = 'SELECT A.FirstName, A.LastName, B.IncidentNumber, B.Date, B.Place, B.CreatedBy
FROM Name A INNER JOIN Incident B
ON A.NameID = B.NameID where lastname IS NOT null ' -- PUT IN A WHERE CLAUSE THAT WILL ALWAYS BE TRUE
---Here is the concept in pseudo code
IF #lastname is not null
BEGIN
SET #SQL = #SQL + 'and lastname = '%' + #lastname + '%'
END
IF #FIRSTNAMEis not null
BEGIN
SET #SQL = #SQL + 'and FIRSTNAME = '%' + #FIRSTNAME+ '%'
END
At the end
EXEC (#SQL)
This will give you any option they put in.

I need to populate my gridview after I select a checkbox from checkboxlist

I need to populate my gridview after I select a checkbox from checkboxlist. I'm trying to use a loop, I also need to hide the gridview if the user unchecks the checkbox. Im useing a sql statement to pull the data. The sql should pull whatever data is associated with the checked box
'Shows Books from selected Category
Protected Sub chkbListControl_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles chkListControl.SelectedIndexChanged
Dim sqlChecked As String = "select * " _
& "from Books, Categories " _
& "where Categories.CategoryCode=Books.CategoryCode " _
& "order by Title;"
Dim sqlUnChecked As String = "select * from Books where Categories.CategoryCode=Books.CategoryCode;"
Dim selectedIndex As Integer = chkListControl.SelectedIndex
Dim i As Integer
If (selectedIndex <> -1) Then
For i = 0 To chkListControl.Items.Count - 1
If chkListControl.Items(i).Selected Then
gvwBookList.DataSource = ReturnTable(sqlChecked)
gvwBookList.DataBind()
Else
gvwBookList.DataSource = ReturnTable(sqlUnChecked)
gvwBookList.DataBind()
gvwBookList.Visible = False
End If
Next
End If
End Sub
You need to modify your sqlchecked like this
dim selectedcategories as string=""
If (selectedIndex <> -1) Then
For i = 0 To chkListControl.Items.Count - 1
If chkListControl.Items(i).Selected Then
if selectedcategories="" then
selectedcategories=chkListControl.Items(i).value
else
selectedcategories &="," & chkListControl.Items(i).value
end if
End If
Next
End If
dim strSQL as string=""
if selectedcategories.trim<>"" then
strSQL = "select * " _
& "from Books, Categories " _
& "where Categories.CategoryCode=Books.CategoryCode and Categories.CategoryCode in (" & selectedcategories & ")" _
& "order by Title;"
else
strSQL="select * from Books where Categories.CategoryCode=Books.CategoryCode;"
end if
gvwBookList.DataSource = ReturnTable(strSQL)
gvwBookList.DataBind()
You can modify above code according to your requirement.

How to delete or add column in SQLITE?

I want to delete or add column in sqlite database
I am using following query to delete column.
ALTER TABLE TABLENAME DROP COLUMN COLUMNNAME
But it gives error
System.Data.SQLite.SQLiteException: SQLite error
near "DROP": syntax error
ALTER TABLE SQLite
SQLite supports a limited subset of ALTER TABLE. The ALTER TABLE command in SQLite allows the user to rename a table or to add a new column to an existing table. It is not possible to rename a column, remove a column, or add or remove constraints from a table.
You can:
create new table as the one you are trying to change,
copy all data,
drop old table,
rename the new one.
SQLite 3.35.0 introduced support for ALTER TABLE DROP COLUMN.
ALTER TABLE
The DROP COLUMN syntax is used to remove an existing column from a table. The DROP COLUMN command removes the named column from the table, and also rewrites the entire table to purge the data associated with that column. The DROP COLUMN command only works if the column is not referenced by any other parts of the schema and is not a PRIMARY KEY and does not have a UNIQUE constraint.
The following syntax will be valid:
ALTER TABLE <TABLENAME> DROP COLUMN <COLUMNNAME>;
ALTER TABLE <TABLENAME> DROP <COLUMNNAME>;
I've wrote a Java implementation based on the Sqlite's recommended way to do this:
private void dropColumn(SQLiteDatabase db,
ConnectionSource connectionSource,
String createTableCmd,
String tableName,
String[] colsToRemove) throws java.sql.SQLException {
List<String> updatedTableColumns = getTableColumns(tableName);
// Remove the columns we don't want anymore from the table's list of columns
updatedTableColumns.removeAll(Arrays.asList(colsToRemove));
String columnsSeperated = TextUtils.join(",", updatedTableColumns);
db.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");
// Creating the table on its new format (no redundant columns)
db.execSQL(createTableCmd);
// Populating the table with the data
db.execSQL("INSERT INTO " + tableName + "(" + columnsSeperated + ") SELECT "
+ columnsSeperated + " FROM " + tableName + "_old;");
db.execSQL("DROP TABLE " + tableName + "_old;");
}
To get the table's column, I used the "PRAGMA table_info":
public List<String> getTableColumns(String tableName) {
ArrayList<String> columns = new ArrayList<String>();
String cmd = "pragma table_info(" + tableName + ");";
Cursor cur = getDB().rawQuery(cmd, null);
while (cur.moveToNext()) {
columns.add(cur.getString(cur.getColumnIndex("name")));
}
cur.close();
return columns;
}
I actually wrote about it on my blog, you can see more explanations there:
http://udinic.wordpress.com/2012/05/09/sqlite-drop-column-support/
As others have pointed out
It is not possible to rename a column, remove a column, or add or
remove constraints from a table.
source : http://www.sqlite.org/lang_altertable.html
While you can always create a new table and then drop the older one.
I will try to explain this workaround with an example.
sqlite> .schema
CREATE TABLE person(
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
age INTEGER,
height INTEGER
);
sqlite> select * from person ;
id first_name last_name age height
---------- ---------- ---------- ---------- ----------
0 john doe 20 170
1 foo bar 25 171
Now you want to remove the column height from this table.
Create another table called new_person
sqlite> CREATE TABLE new_person(
...> id INTEGER PRIMARY KEY,
...> first_name TEXT,
...> last_name TEXT,
...> age INTEGER
...> ) ;
sqlite>
Now copy the data from the old table
sqlite> INSERT INTO new_person
...> SELECT id, first_name, last_name, age FROM person ;
sqlite> select * from new_person ;
id first_name last_name age
---------- ---------- ---------- ----------
0 john doe 20
1 foo bar 25
sqlite>
Now Drop the person table and rename new_person to person
sqlite> DROP TABLE IF EXISTS person ;
sqlite> ALTER TABLE new_person RENAME TO person ;
sqlite>
So now if you do a .schema, you will see
sqlite>.schema
CREATE TABLE "person"(
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
age INTEGER
);
DB Browser for SQLite allows you to add or drop columns.
In the main view, tab Database Structure, click on the table name. A button Modify Table gets enabled, which opens a new window where you can select the column/field and remove it.
At one time this was not directly supported and you would need to follow a four-step process: (1) create a temporary_table, (2) copy the data, (3) drop the old table, and then (4) rename the temporary_table.
But now that these features are supported, all you need to do is upgrade SQLite.
3.35.0 from 2021-03-12 adds ALTER TABLE DROP COLUMN
3.25.0 from 2018-09-15 added ALTER TABLE RENAME COLUMN
3.2.0 from way back in 2005-03-21 added ALTER TABLE ADD COLUMN
Note that there are still some edge cases where these may not work, e.g., you cannot drop a primary key column. See the documentation for more details. When these ALTER TABLE … COLUMN statements do not work, you can fall back to the four-step process.
By the way the four-step process is really a twelve-step process in the docs. But four of those steps are really important, easy to get wrong, and specifically called out in those docs.
http://www.sqlite.org/lang_altertable.html
As you can see in the diagram, only ADD COLUMN is supported. There is a (kinda heavy) workaround, though: http://www.sqlite.org/faq.html#q11
We cannot drop a specific column in SQLite 3. See the FAQ.
As others have pointed out, sqlite's ALTER TABLE statement does not support DROP COLUMN, and the standard recipe to do this does not preserve constraints & indices.
Here's some python code to do this generically, while maintaining all the key constraints and indices.
Please back-up your database before using! This function relies on doctoring the original CREATE TABLE statement and is potentially a bit unsafe - for instance it will do the wrong thing if an identifier contains an embedded comma or parenthesis.
If anyone would care to contribute a better way to parse the SQL, that would be great!
UPDATE I found a better way to parse using the open-source sqlparse package. If there is any interest I will post it here, just leave a comment asking for it ...
import re
import random
def DROP_COLUMN(db, table, column):
columns = [ c[1] for c in db.execute("PRAGMA table_info(%s)" % table) ]
columns = [ c for c in columns if c != column ]
sql = db.execute("SELECT sql from sqlite_master where name = '%s'"
% table).fetchone()[0]
sql = format(sql)
lines = sql.splitlines()
findcol = r'\b%s\b' % column
keeplines = [ line for line in lines if not re.search(findcol, line) ]
create = '\n'.join(keeplines)
create = re.sub(r',(\s*\))', r'\1', create)
temp = 'tmp%d' % random.randint(1e8, 1e9)
db.execute("ALTER TABLE %(old)s RENAME TO %(new)s" % {
'old': table, 'new': temp })
db.execute(create)
db.execute("""
INSERT INTO %(new)s ( %(columns)s )
SELECT %(columns)s FROM %(old)s
""" % {
'old': temp,
'new': table,
'columns': ', '.join(columns)
})
db.execute("DROP TABLE %s" % temp)
def format(sql):
sql = sql.replace(",", ",\n")
sql = sql.replace("(", "(\n")
sql = sql.replace(")", "\n)")
return sql
I rewrote the #Udinic answer so that the code generates table creation query automatically. It also doesn't need ConnectionSource. It also has to do this inside a transaction.
public static String getOneTableDbSchema(SQLiteDatabase db, String tableName) {
Cursor c = db.rawQuery(
"SELECT * FROM `sqlite_master` WHERE `type` = 'table' AND `name` = '" + tableName + "'", null);
String result = null;
if (c.moveToFirst()) {
result = c.getString(c.getColumnIndex("sql"));
}
c.close();
return result;
}
public List<String> getTableColumns(SQLiteDatabase db, String tableName) {
ArrayList<String> columns = new ArrayList<>();
String cmd = "pragma table_info(" + tableName + ");";
Cursor cur = db.rawQuery(cmd, null);
while (cur.moveToNext()) {
columns.add(cur.getString(cur.getColumnIndex("name")));
}
cur.close();
return columns;
}
private void dropColumn(SQLiteDatabase db, String tableName, String[] columnsToRemove) {
db.beginTransaction();
try {
List<String> columnNamesWithoutRemovedOnes = getTableColumns(db, tableName);
// Remove the columns we don't want anymore from the table's list of columns
columnNamesWithoutRemovedOnes.removeAll(Arrays.asList(columnsToRemove));
String newColumnNamesSeparated = TextUtils.join(" , ", columnNamesWithoutRemovedOnes);
String sql = getOneTableDbSchema(db, tableName);
// Extract the SQL query that contains only columns
String oldColumnsSql = sql.substring(sql.indexOf("(")+1, sql.lastIndexOf(")"));
db.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");
db.execSQL("CREATE TABLE `" + tableName + "` (" + getSqlWithoutRemovedColumns(oldColumnsSql, columnsToRemove)+ ");");
db.execSQL("INSERT INTO " + tableName + "(" + newColumnNamesSeparated + ") SELECT " + newColumnNamesSeparated + " FROM " + tableName + "_old;");
db.execSQL("DROP TABLE " + tableName + "_old;");
db.setTransactionSuccessful();
} catch {
//Error in between database transaction
} finally {
db.endTransaction();
}
}
I have improved user2638929 answer and now it can preserves column type, primary key, default value etc.
public static void dropColumns(SQLiteDatabase database, String tableName, Collection<String> columnsToRemove){
List<String> columnNames = new ArrayList<>();
List<String> columnNamesWithType = new ArrayList<>();
List<String> primaryKeys = new ArrayList<>();
String query = "pragma table_info(" + tableName + ");";
Cursor cursor = database.rawQuery(query,null);
while (cursor.moveToNext()){
String columnName = cursor.getString(cursor.getColumnIndex("name"));
if (columnsToRemove.contains(columnName)){
continue;
}
String columnType = cursor.getString(cursor.getColumnIndex("type"));
boolean isNotNull = cursor.getInt(cursor.getColumnIndex("notnull")) == 1;
boolean isPk = cursor.getInt(cursor.getColumnIndex("pk")) == 1;
columnNames.add(columnName);
String tmp = "`" + columnName + "` " + columnType + " ";
if (isNotNull){
tmp += " NOT NULL ";
}
int defaultValueType = cursor.getType(cursor.getColumnIndex("dflt_value"));
if (defaultValueType == Cursor.FIELD_TYPE_STRING){
tmp += " DEFAULT " + "\"" + cursor.getString(cursor.getColumnIndex("dflt_value")) + "\" ";
}else if(defaultValueType == Cursor.FIELD_TYPE_INTEGER){
tmp += " DEFAULT " + cursor.getInt(cursor.getColumnIndex("dflt_value")) + " ";
}else if (defaultValueType == Cursor.FIELD_TYPE_FLOAT){
tmp += " DEFAULT " + cursor.getFloat(cursor.getColumnIndex("dflt_value")) + " ";
}
columnNamesWithType.add(tmp);
if (isPk){
primaryKeys.add("`" + columnName + "`");
}
}
cursor.close();
String columnNamesSeparated = TextUtils.join(", ", columnNames);
if (primaryKeys.size() > 0){
columnNamesWithType.add("PRIMARY KEY("+ TextUtils.join(", ", primaryKeys) +")");
}
String columnNamesWithTypeSeparated = TextUtils.join(", ", columnNamesWithType);
database.beginTransaction();
try {
database.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");
database.execSQL("CREATE TABLE " + tableName + " (" + columnNamesWithTypeSeparated + ");");
database.execSQL("INSERT INTO " + tableName + " (" + columnNamesSeparated + ") SELECT "
+ columnNamesSeparated + " FROM " + tableName + "_old;");
database.execSQL("DROP TABLE " + tableName + "_old;");
database.setTransactionSuccessful();
}finally {
database.endTransaction();
}
}
PS. I used here android.arch.persistence.db.SupportSQLiteDatabase, but you can easyly modify it for use android.database.sqlite.SQLiteDatabase
I guess what you are wanting to do is database migration. 'Drop'ping a column does not exist in SQLite. But you can however, add an extra column by using the ALTER table query.
you can use Sqlitebrowser. In the browser mode, for the respective database and the table, under the tab -database structure,following the option Modify Table, respective column could be removed.
You can use the SQlite Administrator for changing the column names.
Right Click on Table name and select Edit Table.Here you will find the table structure and you can easily rename it.
As SQLite has limited support to ALTER TABLE so you can only ADD column at end of the table OR CHANGE TABLE_NAME in SQLite.
Here is the Best Answer of HOW TO DELETE COLUMN FROM SQLITE?
visit Delete column from SQLite table
As an alternative:
If you have a table with schema
CREATE TABLE person(
id INTEGER PRIMARY KEY,
first_name TEXT,
last_name TEXT,
age INTEGER,
height INTEGER
);
you can use a CREATE TABLE...AS statement like CREATE TABLE person2 AS SELECT id, first_name, last_name, age FROM person;, i.e. leave out the columns you don't want. Then drop the original person table and rename the new one.
Note this method produces a table has no PRIMARY KEY and no constraints. To preserve those, utilize the methods others described to create a new table, or use a temporary table as an intermediate.
This answer to a different question is oriented toward modifying a column, but I believe a portion of the answer could also yield a useful approach if you have lots of columns and don't want to retype most of them by hand for your INSERT statement:
https://stackoverflow.com/a/10385666
You could dump your database as described in the link above, then grab the "create table" statement and an "insert" template from that dump, then follow the instructions in the SQLite FAQ entry "How do I add or delete columns from an existing table in SQLite." (FAQ is linked elsewhere on this page.)
Implementation in Python based on information at http://www.sqlite.org/faq.html#q11.
import sqlite3 as db
import random
import string
QUERY_TEMPLATE_GET_COLUMNS = "PRAGMA table_info(#table_name)"
QUERY_TEMPLATE_DROP_COLUMN = """
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE #tmp_table(#columns_to_keep);
INSERT INTO #tmp_table SELECT #columns_to_keep FROM #table_name;
DROP TABLE #table_name;
CREATE TABLE #table_name(#columns_to_keep);
INSERT INTO #table_name SELECT #columns_to_keep FROM #tmp_table;
DROP TABLE #tmp_table;
COMMIT;
"""
def drop_column(db_file, table_name, column_name):
con = db.connect(db_file)
QUERY_GET_COLUMNS = QUERY_TEMPLATE_GET_COLUMNS.replace("#table_name", table_name)
query_res = con.execute(QUERY_GET_COLUMNS).fetchall()
columns_list_to_keep = [i[1] for i in query_res if i[1] != column_name]
columns_to_keep = ",".join(columns_list_to_keep)
tmp_table = "tmp_%s" % "".join(random.sample(string.ascii_lowercase, 10))
QUERY_DROP_COLUMN = QUERY_TEMPLATE_DROP_COLUMN.replace("#table_name", table_name)\
.replace("#tmp_table", tmp_table).replace("#columns_to_keep", columns_to_keep)
con.executescript(QUERY_DROP_COLUMN)
con.close()
drop_column(DB_FILE, TABLE_NAME, COLUMN_NAME)
This script first makes random temporary table and inserts data of only necessary columns except the one that will will be dropped. Then restores the original table based on the temporary table and drops the temporary table.
My solution, only need to call this method.
public static void dropColumn(SQLiteDatabase db, String tableName, String[] columnsToRemove) throws java.sql.SQLException {
List<String> updatedTableColumns = getTableColumns(db, tableName);
updatedTableColumns.removeAll(Arrays.asList(columnsToRemove));
String columnsSeperated = TextUtils.join(",", updatedTableColumns);
db.execSQL("ALTER TABLE " + tableName + " RENAME TO " + tableName + "_old;");
db.execSQL("CREATE TABLE " + tableName + " (" + columnsSeperated + ");");
db.execSQL("INSERT INTO " + tableName + "(" + columnsSeperated + ") SELECT "
+ columnsSeperated + " FROM " + tableName + "_old;");
db.execSQL("DROP TABLE " + tableName + "_old;");
}
And auxiliary method to get the columns:
public static List<String> getTableColumns(SQLiteDatabase db, String tableName) {
ArrayList<String> columns = new ArrayList<>();
String cmd = "pragma table_info(" + tableName + ");";
Cursor cur = db.rawQuery(cmd, null);
while (cur.moveToNext()) {
columns.add(cur.getString(cur.getColumnIndex("name")));
}
cur.close();
return columns;
}
At least as of version 3.37.0, sqlite3 does support DROP COLUMN
public void DeleteColFromTable(String DbName, String TableName, String ColName){
SQLiteDatabase db = openOrCreateDatabase(""+DbName+"", Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS "+TableName+"(1x00dff);");
Cursor c = db.rawQuery("PRAGMA table_info("+TableName+")", null);
if (c.getCount() == 0) {
} else {
String columns1 = "";
String columns2 = "";
while (c.moveToNext()) {
if (c.getString(1).equals(ColName)) {
} else {
columns1 = columns1 + ", " + c.getString(1) + " " + c.getString(2);
columns2 = columns2 + ", " + c.getString(1);
}
if (c.isLast()) {
db.execSQL("CREATE TABLE IF NOT EXISTS DataBackup (" + columns1 + ");");
db.execSQL("INSERT INTO DataBackup SELECT " + columns2 + " FROM "+TableName+";");
db.execSQL("DROP TABLE "+TableName+"");
db.execSQL("ALTER TABLE DataBackup RENAME TO "+TableName+";");
}
}
}
}
and just call a method
DeleteColFromTable("Database name","Table name","Col name which want to delete");
Kotlin solution, based on here , but also:
Ensures the temporary table doesn't already exist
Has a fix of checking the type for the default value, as it returns String type when it's an Integer (reported about this issue here).
Avoids doing anything if the columns that you wish to remove don't exist anyway.
object DbUtil {
/** https://stackoverflow.com/a/51587449/878126 */
#JvmStatic
fun dropColumns(database: SQLiteDatabase, tableName: String,
columnsToRemove: Collection<String>) {
val columnNames: MutableList<String> = ArrayList()
val columnNamesWithType: MutableList<String> = ArrayList()
val primaryKeys: MutableList<String> = ArrayList()
val query = "pragma table_info($tableName);"
val cursor = database.rawQuery(query, null)
val columnDefaultIndex = cursor.getColumnIndex("dflt_value")
val columnNameIndex = cursor.getColumnIndex("name")
val columnTypeIndex = cursor.getColumnIndex("type")
val columnNotNullIndex = cursor.getColumnIndex("notnull")
val columnPrimaryKeyIndex = cursor.getColumnIndex("pk")
val sb = StringBuilder()
var foundColumnsToRemove = false
while (cursor.moveToNext()) {
val columnName = cursor.getString(columnNameIndex)
if (columnsToRemove.contains(columnName)) {
foundColumnsToRemove = true
continue
}
val columnType = cursor.getString(columnTypeIndex)
val isNotNull = cursor.getInt(columnNotNullIndex) == 1
val isPrimaryKey = cursor.getInt(columnPrimaryKeyIndex) == 1
columnNames.add(columnName)
sb.clear()
sb.append("`$columnName` $columnType ")
if (isNotNull)
sb.append(" NOT NULL ")
if (cursor.getType(columnDefaultIndex) != Cursor.FIELD_TYPE_NULL) {
//has default value
when (columnType.uppercase()) {
"INTEGER" -> sb.append(" DEFAULT ${cursor.getInt(columnDefaultIndex)} ")
"TEXT" -> sb.append(" DEFAULT \"${cursor.getString(columnDefaultIndex)}\" ")
"REAL" -> sb.append(" DEFAULT ${cursor.getFloat(columnDefaultIndex)} ")
}
}
columnNamesWithType.add(sb.toString())
if (isPrimaryKey)
primaryKeys.add("`$columnName`")
}
cursor.close()
if (!foundColumnsToRemove)
return
val columnNamesSeparated = TextUtils.join(", ", columnNames)
if (primaryKeys.size > 0)
columnNamesWithType.add("PRIMARY KEY(${TextUtils.join(", ", primaryKeys)})")
val columnNamesWithTypeSeparated = TextUtils.join(", ", columnNamesWithType)
database.beginTransaction()
try {
var newTempTableName: String
var counter = 0
while (true) {
newTempTableName = "${tableName}_old_$counter"
if (!isTableExists(database, newTempTableName))
break
++counter
}
database.execSQL("ALTER TABLE $tableName RENAME TO $newTempTableName;")
database.execSQL("CREATE TABLE $tableName ($columnNamesWithTypeSeparated);")
database.execSQL(
"INSERT INTO $tableName ($columnNamesSeparated) SELECT $columnNamesSeparated FROM $newTempTableName;")
database.execSQL("DROP TABLE ${newTempTableName};")
database.setTransactionSuccessful()
} finally {
database.endTransaction()
}
}
#JvmStatic
fun isTableExists(database: SQLiteDatabase, tableName: String): Boolean {
database.rawQuery(
"select DISTINCT tbl_name from sqlite_master where tbl_name = '$tableName'", null)
?.use {
return it.count > 0
} ?: return false
}
}
You can also now use DB browser for SQLite to manipulate columns

Resources