Copy rows from table to another - sqlite

I want to copy the rows of a table OLD into another table NEW.
INSERT INTO NEW
SELECT date, kind, id, product, version, quantity FROM OLD;
The table OLD has a column kind which is VARCHAR and contains words like insert, extract, delete. In the NEW table this column is an INTEGER. Is there a way to say that if you find delete insert 1, if you find extract insert 2 etc.. ?

This should work for you,
INSERT INTO Destination SELECT * FROM Source;
See SQL As Understood By SQLite: INSERT for a formal definition.

You can use a CASE statement to replace the string labels with integers:
INSERT INTO NEW
SELECT date,
CASE WHEN kind = 'delete' THEN 1
WHEN kind = 'extract' THEN 2
ELSE ...
END,
product,
version,
quantity
FROM OLD;
This assumes that the columns line up correctly, and all the other column types match.

Related

SQLite: How to UPDATE column using count(*) range?

I'm not sure I'm using right terminology here.
Basically I want to update entire "id" column using count(*) [485] as a delimiter, in an ascending order, so the resulting row value will correspond with rownumber (not the rowid).
If I understand you correctly, this should work for you:
UPDATE tbl_name SET id=rowid
EDIT
If that's is the case -> then it's a lit bit more tricky, since SQlite doesn't support variables declaration.
So what I suggest is,
To create temporary table from select of your original table which makes it's rowids to be as row numbers 1,2,3 etc...
Set it's rowNum (the needed row number column) as each rowid
Then replace the original table with it.
Like this: (assume original table called orig_name)
CREATE TABLE tmp_tbl AS SELECT rowNum FROM orig_name;
UPDATE tmp_tbl SET rowNum=rowid;
DROP TABLE orig_name;
CREATE TABLE orig_name AS SELECT rowNum FROM tmp_tbl;
DROP TABLE tmp_tbl;
Try this: http://www.sqlite.org/lang_createtable.html#rowid
You can use some inner database variables such as rowid, oid etc to get what you need.
[edit]
Think I just understood what you meant, you want for each insert action, add a value that is the total count of rows currently in the table?
If so, try something like this:
UPDATE tbl_name
SET id = (select count(*) from tbl_name)
WHERE yada_yada_yada

Make select query return in order of arguments

I have a relatively simple select query which asks for rows by an column value (this is not controlled by me). I pass in a variable argument of id values to be returned. Here's an example:
select * from team where id in (2, 1, 3)
I'm noticing that as the database changes its order over time, my results are changing order as well. Is there a way to make SQLite guarantee results in the same order as the arguments?
If you could have so many IDs that the query becomes unwieldy, use a temporary table to store them:
CREATE TEMPORARY TABLE SearchIDs (
ID,
OrderNr INTEGER PRIMARY KEY
);
(The OrderNr column is autoincrementing so that it automatically gets proper values when you insert values.)
To do the search, you have to fill this table:
INSERT INTO SearchIDs(ID) VALUES (2), (1), (3) ... ;
SELECT Team.*
FROM Team
JOIN SearchIDs USING (ID)
ORDER BY SearchIDs.OrderNr;
DELETE FROM SearchIDs;
Try this!
select * from team order by
case when 2 then 0
when 1 then 1
when 3 then 2
end

How to DELETE a row with a GUID Value in SQLite

I have a column in SQLite of GUID type, I have tried a query like this, and it returns no error, but the row is not deleted
DELETE FROM MyTable WHERE Id='4ffbd580-b17d-4731-b162-ede8d698e026';
In SQLite Browser the Id values look like binary values, they have strange characters.
I also have tried this, but still does not work
DELETE FROM MyTable WHERE Id='{4ffbd580-b17d-4731-b162-ede8d698e026}';
I know I'm late for this, but it might just be useful for someone with the same problem.
I have a uniqueidentifier type of column in one of my tables and when I execute a select query without any conditions, it returns the result guid column values in this format -
{000B6A69-04D6-C557-7EA3-08CF8C8AD84B}
(Yes, with the braces)
I found out using typeof() function that my guid column values had been stored as text. So, I just tried out four different statements and luckily, the 4th one worked -
1. select myGuidColumn, typeof(myGuidColumn) from MyTable WHERE [myGuidColumn] = '000B6A69-04D6-C557-7EA3-08CF8C8AD84B' --didn't work
2. select myGuidColumn, typeof(myGuidColumn) from MyTable WHERE [myGuidColumn] = '{000B6A69-04D6-C557-7EA3-08CF8C8AD84B}' --didn't work
3. select myGuidColumn, typeof(myGuidColumn) from MyTable WHERE [myGuidColumn] LIKE '{000B6A69-04D6-C557-7EA3-08CF8C8AD84B}' --didn't work
4. select myGuidColumn, typeof(myGuidColumn) from MyTable WHERE [myGuidColumn] LIKE '000B6A69-04D6-C557-7EA3-08CF8C8AD84B' --it works!
Try this command. Id is a probably a binary blob field
DELETE FROM MyTable WHERE Id= X'4ffbd580b17d4731b162ede8d698e026';

How do I add a new column in between two columns?

I have a table with columns name, qty, rate. I need to add a new column COLNew in between the name and qty columns. How do I add a new column in between two columns?
You have two options.
First, you could simply add a new column with the following:
ALTER TABLE {tableName} ADD COLUMN COLNew {type};
Second, and more complicatedly, but would actually put the column where you want it, would be to create the new table with the missing column and a temporary new name:
CREATE TABLE {tempNewTableName} (name TEXT, COLNew {type} DEFAULT {defaultValue}, qty INTEGER, rate REAL);
And populate it with the old data:
INSERT INTO {tempNewTableName} (name, qty, rate) SELECT name, qty, rate FROM OldTable;
Then delete the old table:
DROP TABLE OldTable;
Then rename the new table to have the name of the OldTable:
ALTER TABLE {tempNewTableName} RENAME TO OldTable;
I'd much prefer the second option, as it will allow you to completely rename everything if need be.
You don't add columns between other columns in SQL, you just add them. Where they're put is totally up to the DBMS. The right place to ensure that columns come out in the correct order is when you select them.
In other words, if you want them in the order {name,colnew,qty,rate}, you use:
select name, colnew, qty, rate from ...
With SQLite, you need to use alter table, an example being:
alter table mytable add column colnew char(50)
You can add new column with the query
ALTER TABLE TableName ADD COLUMN COLNew CHAR(25)
But it will be added at the end, not in between the existing columns.
SQLite has limited ALTER TABLE support that you can use to add a column to the end of a table or to change the name of a table.
If you want to make more complex changes in the structure of a table, you will have to recreate the table. You can save existing data to a temporary table, drop the old table, create the new table, then copy the data back in from the temporary table.
For example, suppose you have a table named "t1" with columns names "a" and "c" and that you want to insert column "b" from this table. The following steps illustrate how this could be done:
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,c);
INSERT INTO t1_backup SELECT a,c FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b, c);
INSERT INTO t1 SELECT a,c FROM t1_backup;
DROP TABLE t1_backup;
COMMIT;
Now you are ready to insert your new data like so:
UPDATE t1 SET b='blah' WHERE a='key'
ALTER TABLE {tableName} ADD COLUMN COLNew {type};
UPDATE {tableName} SET COLNew = {base on {type} pass value here};
This update is required to handle the null value, inputting a default value as you require. As in your case, you need to call the SELECT query and you will get the order of columns, as paxdiablo already said:
SELECT name, colnew, qty, rate FROM{tablename}
and in my opinion, your column name to get the value from the cursor:
private static final String ColNew="ColNew";
String val=cursor.getString(cursor.getColumnIndex(ColNew));
so if the index changes your application will not face any problems.
This is the safe way in the sense that otherwise, if you are using CREATE temptable or RENAME table or CREATE, there would be a high chance of data loss if not handled carefully, for example in the case where your transactions occur while the battery is running out.
I was facing the same problem and the second method proposed in the accepted answer, as noted in the comments, can be problematic when dealing with foreign keys.
My workaround is to export the database to a sql file making sure that the INSERT statements include column names. I do it using DB Browser for SQLite which has an handy feature for that. After that you just have to edit the create table statement and insert the new column where you want it and recreate the db.
In *nix like systems is just something along the lines of
cat db.sql | sqlite3 database.db
I don't know how feasible this is with very big databases, but it worked in my case.
I seldom add Answers to 11 year old questions. That said the answer with a lot of votes has a misleading line of code. I say misleading because I tried it and had no success. Here is the line of code I am referencing.
ALTER TABLE {tableName} RENAME TO TempOldTable
This is the line I tried in my first try at adding a Column into a DB Table that had already been created. It FAILED but WHY might be a better question. Any way here is the failing line of code.
Dim tb As String = "IncomeTable"
Dim sqlCmd As String = "$ALTER TABLE" '{tb}' "ADD COLUMN itNumVisit INTEGER"
So here is the final code that adds a new Column in my case an INTEGER type.
Private Sub btnCopyTable_Click(sender As Object, e As EventArgs) Handles btnCopyTable.Click
Dim sqlCmd As String = "ALTER TABLE IncomeTable ADD COLUMN itNumVisit INTEGER"
Try
Using conn As New SQLiteConnection($"Data Source = '{gv_dbName}';Version=3;")
conn.Open()
Using cmd As New SQLiteCommand(sqlCmd, conn)
cmd.ExecuteNonQuery()
End Using
End Using
Catch ex As Exception
MsgBox("It Failed")
End Try
End Sub
Notice the STRING sqlCmd is all one String. Just in case someone tried the accepted Answer!

How do I find out if a SQLite index is unique? (With SQL)

I want to find out, with an SQL query, whether an index is UNIQUE or not. I'm using SQLite 3.
I have tried two approaches:
SELECT * FROM sqlite_master WHERE name = 'sqlite_autoindex_user_1'
This returns information about the index ("type", "name", "tbl_name", "rootpage" and "sql"). Note that the sql column is empty when the index is automatically created by SQLite.
PRAGMA index_info(sqlite_autoindex_user_1);
This returns the columns in the index ("seqno", "cid" and "name").
Any other suggestions?
Edit: The above example is for an auto-generated index, but my question is about indexes in general. For example, I can create an index with "CREATE UNIQUE INDEX index1 ON visit (user, date)". It seems no SQL command will show if my new index is UNIQUE or not.
PRAGMA INDEX_LIST('table_name');
Returns a table with 3 columns:
seq Unique numeric ID of index
name Name of the index
unique Uniqueness flag (nonzero if UNIQUE index.)
Edit
Since SQLite 3.16.0 you can also use table-valued pragma functions which have the advantage that you can JOIN them to search for a specific table and column. See #mike-scotty's answer.
Since noone's come up with a good answer, I think the best solution is this:
If the index starts with "sqlite_autoindex", it is an auto-generated index for a single UNIQUE column
Otherwise, look for the UNIQUE keyword in the sql column in the table sqlite_master, with something like this:
SELECT * FROM sqlite_master WHERE type = 'index' AND sql LIKE '%UNIQUE%'
you can programmatically build a select statement to see if any tuples point to more than one row. If you get back three columns, foo, bar and baz, create the following query
select count(*) from t
group by foo, bar, baz
having count(*) > 1
If that returns any rows, your index is not unique, since more than one row maps to the given tuple. If sqlite3 supports derived tables (I've yet to have the need, so I don't know off-hand), you can make this even more succinct:
select count(*) from (
select count(*) from t
group by foo, bar, baz
having count(*) > 1
)
This will return a single row result set, denoting the number of duplicate tuple sets. If positive, your index is not unique.
You are close:
1) If the index starts with "sqlite_autoindex", it is an auto-generated index for the primary key . However, this will be in the sqlite_master or sqlite_temp_master tables depending depending on whether the table being indexed is temporary.
2) You need to watch out for table names and columns that contain the substring unique, so you want to use:
SELECT * FROM sqlite_master WHERE type = 'index' AND sql LIKE 'CREATE UNIQUE INDEX%'
See the sqlite website documentation on Create Index
As of sqlite 3.16.0 you could also use pragma functions:
SELECT distinct il.name
FROM sqlite_master AS m,
pragma_index_list(m.name) AS il,
pragma_index_info(il.name) AS ii
WHERE m.type='table' AND il.[unique] = 1;
The above statement will list all names of unique indexes.
SELECT DISTINCT m.name as table_name, ii.name as column_name
FROM sqlite_master AS m,
pragma_index_list(m.name) AS il,
pragma_index_info(il.name) AS ii
WHERE m.type='table' AND il.[unique] = 1;
The above statement will return all tables and their columns if the column is part of a unique index.
From the docs:
The table-valued functions for PRAGMA feature was added in SQLite version 3.16.0 (2017-01-02). Prior versions of SQLite cannot use this feature.

Resources