how to set primary key in csv imported by sqlite - sqlite

I have the following table stored as a csv file:
project_number,project_name
1,project_1
2,project_2
3,project_3
I figured out how to import this and show its schema in an sqlite3 database as follows:
sqlite> .mode csv
sqlite> .import
sqlite> .import test.csv test
sqlite> .schema test
CREATE TABLE test(
"project_number" TEXT,
"project_name" TEXT
);
I would like to now set the column project_number as my primary key and also set it to be an integer. I understand from previous questions that this is difficult to do by altering the original table, so I tried to create a new table an populated using a combination of create table, create table as, insert into and select * from as indicated here
sqlite> create table test_2 (project_name text, project_number primary key);
sqlite> insert into test_2 (select project_name, project_number from test);
Error: near "select": syntax error
But as you can see this caused a syntax error and I don't understand why. How do I set the primary key for tables imported from csvs?

You can also create the table first and then import data into it. Assuming a Linux or Unix environment:
sqlite> create table test(project_number integer primary key, project_name text);
sqlite> .mode csv
sqlite> .import '| tail -n +2 test.csv' test
will skip the first header row in the file and insert the rest.

Try this:
insert into test_2 (project_number, project_name)
select project_number, project_name from test;
I guess insert into example at https://dba.stackexchange.com/a/41108/26454 is wrong: one need to list columns after table name, reference.

Related

How to import csv file to sqlite with correct data types

When I import a csv file to sqlite database, it imports number as string to integer column, how can I fix this? A line from my csv file like this:
31,c,BB ROSE - 031,c31,,9,7,0,"142,000",0
CSV files do no have data types; everything is a string.
To convert all values in a column into a number, use something like this:
UPDATE MyTable SET MyColumn = CAST(MyColumn AS INTEGER)
When importing csv files, SQLite assumes all fields are text fields. So you need to perform some extra steps in order to set the correct data types.
However, it is my understanding that you cannot use the ALTER TABLE statement to modify a column in SQLite. Instead, you will need to rename the table, create a new table, and copy the data into the new table.
https://www.techonthenet.com/sqlite/tables/alter_table.php
So suppose I have an employees.csv file I want to import into SQLite database with the correct data types.
employee_id,last_name,first_name,hire_date
1001,adams,john,2010-12-12
1234,griffin,meg,2000-01-01
2233,simpson,bart,1990-02-23
First, create a SQLite database called mydb.sqlite and import employees.csv into a SQLite table called employees.
# create sqlite database called mydb.sqlite
# import data from 'employees.csv' into a SQLite table called 'employees'
# unfortunately, sqlite assumes all fields are text fields
$ sqlite3 mydb.sqlite
sqlite> .mode csv
sqlite> .import employees.csv employees
sqlite> .quit
At this point, the data is imported as text. Let's first get the employees schema from the database and save it to employees.sql.We can use this to create a new script that would rename the table, create a new table, and copy the data into the new table.
$ sqlite3 mydb.sqlite
sqlite> .once employees.sql
sqlite> .schema employees
sqlite> .quit
You should now have employees.sql with the following schema:
CREATE TABLE employees(
"employee_id" TEXT,
"last_name" TEXT,
"first_name" TEXT,
"hire_date" TEXT
);
Let's now create a SQL filed called alterTable.sql that would rename the table, create a new table, and copy the data into the new table.
alterTable.sql
PRAGMA foreign_keys=off;
BEGIN TRANSACTION;
ALTER TABLE employees RENAME TO _employees_old;
CREATE TABLE employees
( "employee_id" INTEGER,
"last_name" TEXT,
"first_name" TEXT,
"hire_date" NUMERIC
);
INSERT INTO employees ("employee_id", "last_name", "first_name", "hire_date")
SELECT "employee_id", "last_name", "first_name", "hire_date"
FROM _employees_old;
COMMIT;
PRAGMA foreign_keys=on;
Finally, we can execute SQL in alterTable.sql and drop the old renamed table
$ sqlite3 mydb.sqlite
sqlite> .read alterTable.sql
sqlite> drop table _employees_old;
At this point, the imported employee data should have the correct data types instead of the default text field.
If you do it this way, you don't have to worry about headers in csv file being imported as data. Other methods might require you delete the header either before or after importing the csv file.
You just need to create the table first with correct types and then the CSV-import will keep this types, because the table already exists.
Here a sample:
create table table1(name TEXT, wert INT);
.mode csv
.separator ";"
.import "d:/temp/test.csv" table1
If you need to delete an imported header-line then use something like this after the import:
delete from table1 where rowid=1;
or use this in case you already did multiple imports into the same table:
delete from [table1] where "name"='name'; -- try to use a name of an INT-column for this.
at the end you can just check the correct import like this:
.header ON
select * from table1 order by wert;
In SQLite, you cannot change the type affinities of columns. Therefore you should create your table and then .import your CSV file into the table. If your CSV file has a header, that will be treated as data upon import. You can either delete the header before importing (in the CSV file), or delete the header after import (in the table). Since the typeof all the header fields will be TEXT, you can easily find this header in a table where some columns have numeric type affinities.
Import CSV file into SQLite.
Go to Database Structure and select imported CSV file
select modify table from the tab
select field one and change name to desired name of column.
Next select the desired data type from the drop down menu. You can now change from Text to Integer or Numeric depending on the data you are working with
I am using sqlite 3.39.4, I would do as follows:
as suggested above create a new table 'newtable' with the right types, then to import data from your 'mycsvtable.csv', type
.mode csv
.import --skip 1 mycsvtable.csv newtable
the --skip 1 avoids the first row if you have headers in your csv

sqlite tables don't need column names?

In sqlite I was able to create a table with the following command:
create table myTable(varchar, date, int);
Notice that there are no column names! I discovered this when I used column names, and when I executed a where statement, it didn't work with the column name, but it worked when I specified the variable type instead. What's up with that?
But they became names instead of datatypes:
sqlite> create table myTable(varchar, date, int);
sqlite> .headers on
sqlite> insert into myTable Values(1,1,1);
sqlite> select * from myTable;
varchar|date|int
1|1|1

How can one see the structure of a table in SQLite? [duplicate]

This question already has answers here:
Is there an SQLite equivalent to MySQL's DESCRIBE [table]?
(7 answers)
Closed 7 years ago.
How can I see the structure of table in SQLite as desc was in Oracle?
PRAGMA table_info(table_name);
This will work for both: command-line and when executed against a connected database.
A link for more details and example. thanks
SQLite Pragma Command
Invoke the sqlite3 utility on the database file, and use its special dot commands:
.tables will list tables
.schema [tablename] will show the CREATE statement(s) for a table or tables
There are many other useful builtin dot commands -- see the documentation at http://www.sqlite.org/sqlite.html, section Special commands to sqlite3.
Example:
sqlite> entropy:~/Library/Mail>sqlite3 Envelope\ Index
SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
addresses ews_folders subjects
alarms feeds threads
associations mailboxes todo_notes
attachments messages todos
calendars properties todos_deleted_log
events recipients todos_server_snapshot
sqlite> .schema alarms
CREATE TABLE alarms (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, alarm_id,
todo INTEGER, flags INTEGER, offset_days INTEGER,
reminder_date INTEGER, time INTEGER, argument,
unrecognized_data BLOB);
CREATE INDEX alarm_id_index ON alarms(alarm_id);
CREATE INDEX alarm_todo_index ON alarms(todo);
Note also that SQLite saves the schema and all information about tables in the database itself, in a magic table named sqlite_master, and it's also possible to execute normal SQL queries against that table. For example, the documentation link above shows how to derive the behavior of the .schema and .tables commands, using normal SQL commands (see section: Querying the database schema).
You can query sqlite_master
SELECT sql FROM sqlite_master WHERE name='foo';
which will return a create table SQL statement, for example:
$ sqlite3 mydb.sqlite
sqlite> create table foo (id int primary key, name varchar(10));
sqlite> select sql from sqlite_master where name='foo';
CREATE TABLE foo (id int primary key, name varchar(10))
sqlite> .schema foo
CREATE TABLE foo (id int primary key, name varchar(10));
sqlite> pragma table_info(foo)
0|id|int|0||1
1|name|varchar(10)|0||0
You should be able to see the schema by running
.schema <table>
.schema TableName
Where TableName is the name of the Table
You will get the structure by typing the command:
.schema <tableName>
If you are using PHP you can get it this way:
<?php
$dbname = 'base.db';
$db = new SQLite3($dbname);
$sturturequery = $db->query("SELECT sql FROM sqlite_master WHERE name='foo'");
$table = $sturturequery->fetchArray();
echo '<pre>' . $table['sql'] . '</pre>';
$db->close();
?>
You can use the Firefox add-on called SQLite Manager to view the database's structure clearly.

ALTER COLUMN in sqlite

How do I alter column in sqlite?
This is in Postgresql
ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL;
I believe there is no ALTER COLUMN in sqlite at all, only ALTER TABLE is supported.
Any idea? Thanks!
There's no ALTER COLUMN in sqlite.
I believe your only option is to:
Rename the table to a temporary name
Create a new table without the NOT NULL constraint
Copy the content of the old table to the new one
Remove the old table
This other Stackoverflow answer explains the process in details
While it is true that the is no ALTER COLUMN, if you only want to rename the column, drop the NOT NULL constraint, or change the data type, you can use the following set of dangerous commands:
PRAGMA writable_schema = 1;
UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';
PRAGMA writable_schema = 0;
You will need to either close and reopen your connection or vacuum the database to reload the changes into the schema.
For example:
Y:\> **sqlite3 booktest**
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> **create table BOOKS ( title TEXT NOT NULL, publication_date TEXT NOT
NULL);**
sqlite> **insert into BOOKS VALUES ("NULLTEST",null);**
Error: BOOKS.publication_date may not be NULL
sqlite> **PRAGMA writable_schema = 1;**
sqlite> **UPDATE SQLITE_MASTER SET SQL = 'CREATE TABLE BOOKS ( title TEXT NOT
NULL, publication_date TEXT)' WHERE NAME = 'BOOKS';**
sqlite> **PRAGMA writable_schema = 0;**
sqlite> **.q**
Y:\> **sqlite3 booktest**
SQLite version 3.7.4
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> **insert into BOOKS VALUES ("NULLTEST",null);**
sqlite> **.q**
REFERENCES FOLLOW:
pragma writable_schema
When this pragma is on, the SQLITE_MASTER tables in which database can be changed using ordinary UPDATE, INSERT, and DELETE statements. Warning: misuse of this pragma can easily result in a corrupt database file.
[alter table](From http://www.sqlite.org/lang_altertable.html)
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.
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. But you can alter table column datatype or other property by the following steps.
BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,b);
INSERT INTO t1_backup SELECT a,b FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b);
INSERT INTO t1 SELECT a,b FROM t1_backup;
DROP TABLE t1_backup;
COMMIT
For more detail you can refer the link.
CREATE TABLE temp_Table(x,y[,etc]);
INSERT INTO temp_Table SELECT * FROM Table;
DROP TABLE Table;
ALTER TABLE temp_Table RENAME TO Table;
Thanks for helping me to find a definitive method!
ALTER COLUMN does not exist in SQLite.
Only Supported alter operations:
Alter Table Name
Alter Table Column Name
Add New Column
Drop Column
Alex Jasmin's answer shows possible way
Reference:
Sqlite Alter Table

sqlite SELECT returns all records when querying a column for a value with the same name as the column

$ sqlite3 test.db
SQLite version 3.6.21
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> CREATE TABLE test(foo text);
sqlite> INSERT INTO test VALUES ("foo");
sqlite> INSERT INTO test VALUES ("bar");
sqlite> SELECT * FROM test WHERE foo="foo";
foo
bar
sqlite>
It seems that the query treats "foo" as a reference to the name of the column, rather than as a string constant. How do I get this query to only return foo, not bar? Are there options besides renaming the column?
Sqlite3 Keywords
sqlite> SELECT * FROM test WHERE foo='foo';
use single quotes.

Resources