To have launchd start postgresql now and restart at login:
brew services start postgresql
Or, if you don't want/need a background service you can just run:
pg_ctl -D /usr/local/var/postgres start
port 5432 is default
psql postgres
psql -d <database_name> -U myUser -W
psql -h <hostname> -p <port_no> -U <db_username> -d <database_name> -W
psql -h ec2-54-225-89-156.compute-1.amazonaws.com -p 5432 -U pmhuletkaeiyep -d d59asl859nm30e -W
\q to quit/exit
\du
postgresql://localhost/my_database
postgresql://localhost/my_database?sslmode=require
DATABASE_URL=postgres://USERNAME:PASSWORD@HOSTNAME:5432/DATABASENAME
Heroku Admin:
heroku pg:psql postgresql-graceful-74509
Better to use Postico (MacOS) or similar instead.
Tip: table names as singular (Company, Person) – https://stackoverflow.com/a/5841297/449227
e.g. WHERE person.company_id = company.id
First psql postgres, then:
CREATE DATABASE my_database;
Optional:
GRANT ALL PRIVILEGES ON DATABASE my_database TO yourusername;
\connect my_database
\list my_database
\connect: connect to database
List databases
\list
Delete database
DROP DATABASE my_database;
ALTER DATABASE "db" RENAME TO "newdb";
\dt
List all:
\dt *.*
List users:
\du
Current user:
SELECT current_user;
Create user
CREATE USER username [WITH PASSWORD 'password'];
serial: same asint(use for relations) except that PostgreSQL will automatically generate and populate values.- Text:
char(n): paddedvarchar(n)text
- Numbers:
smallint: 2-byte signed integer that has a range from -32,768 to 32,767.int,integer: a 4-byte integer that has a range from -2,147,483,648 to -2,147,483,647.realor float8: double-precision (8-byte) floating-point number.float(n): floating-point number whose precision, at least, n, up to a maximum of 8 bytes.numericornumeric(p,s): real number with p digits with s number after the decimal point. Thenumeric(p,s)is the exact number.
boolean: true/false, t/f- Time & Date:
timestamptz: (DEFAULT now()) timezone-aware timestamp data type. It is the abbreviation for timestamp with time zone. PostgreSQL’s extensiontimestamp: stores both date and time values.date: stores the date values only.time: stores the time of day values.interval: stores periods of time.
- Binary & JSON:
bytea: blob binaryjson, jsonb
- Arrays:
text[],integer[]: e.g.SET string_array='{Word 1, Word 2}' - Enums:
CREATE TYPE project_status AS ENUM ('not-started');
COPY domain_update TO './data/domain_update.csv' DELIMITER ',' CSV HEADER;
https://www.npmjs.com/package/pg
NOTE: if you have connection timeout issues, try upgrading pg:
yarn remove pg; yarn add pg
Simple client:
const { Client } = require('pg')
const postgresOptions = {
connectionString: config.databaseUrl,
// max: 10, // default 10
// connectionTimeoutMillis: 1000, // default 0 = no timeout
// idleTimeoutMillis: 1000, // default 10000 ms
// ssl: { rejectUnauthorized: false },
}
// const results = await runDatabaseFunction(async (client) => client.query(sqlString))
const runDatabaseFunction = async function (functionToRun) {
// Connect db
const client = new Client(postgresOptions)
await client.connect()
// Run function
const { rows } = await client.query(sqlString)
// OR: const results = await functionToRun(client)
// Release db
await client.end()
return results
}
With connection pooling:
const { Pool } = require('pg')
const pool = new Pool(postgresOptions)
// const results = await runDatabaseFunction(async (client) => client.query(sqlString))
module.exports.runDatabaseFunction = async function (functionToRun) {
// Connect db
const client = await pool.connect()
// Run function
const { rows } = await client.query(sqlString)
// OR: const results = await functionToRun(client)
// Release db
await client.end() // used?
await client.release()
return results
}
https://stackoverflow.com/questions/21759852/easier-way-to-update-data-with-node-postgres
Select:
const getCompany = async function (pool, req, res, next) {
const sqlString = `SELECT * FROM company WHERE id = $1;`
const { rows } = await pool.query(sqlString, [req.params.id])
res.json(rows[0])
}
Insert:
// sqlCreate('person', { person values... })
const sqlCreate = (tableName, object) => {
const fieldNames = Object.keys(object).join(', ')
const fieldCounters = Object.keys(object).map((fieldName, index) => `$${index + 1}`).join(', ')
const text = `INSERT INTO ${tableName}(${fieldNames}) VALUES(${fieldCounters})`
const values = Object.values(object)
return { text, values }
}
Update:
// sqlUpdate('person', { id: person.id }, { person values... })
const sqlUpdate = (tableName, query, newValues) => {
const fieldDefinitions = Object.keys(newValues).map((fieldName, index) => `${fieldName} = ($${index + 2})`).join(', ')
const queryFieldName = Object.keys(query)[0]
const text = `UPDATE ${tableName} SET ${fieldDefinitions} WHERE ${queryFieldName}=($1)`
const values = [Object.values(query)[0], ...Object.values(newValues)]
return { text, values }
}
SELECT * FROM table WHERE id = 123;
const sqlString = `SELECT
font.id, font.name,
category.name AS category_name,
source.name AS source_name,
creator.name AS creator_name
FROM font
LEFT JOIN category_font ON (category_font.font_id = font.id)
LEFT JOIN category ON (category.id = category_font.category_id)
LEFT JOIN source ON (source.id = font.source_id)
LEFT JOIN creator ON (creator.id = font.creator_id)
WHERE true
${name ? `AND font.name ILIKE '${name}%'` : ''}
${category ? `AND category.name = '${category}'` : ''}
${weight ? `AND font.variants ILIKE '%${weight}%'` : ''}
${source ? `AND source.name = '${source}'` : ''}
LIMIT 100
;`
SELECT * FROM table WHERE columnName ILIKE 'A%';
SELECT * FROM company WHERE name ILIKE '%weld%';
SELECT * FROM company WHERE website NOT ILIKE 'http%'
Tip: you can use LOWER() for lowercase formatting.
SELECT * FROM person WHERE contact_status_date < '2019-02-09';
SELECT * FROM updates WHERE date_update BETWEEN '2019-01-05' AND '2019-01-10';
WHERE date_update::date BETWEEN DATE '2025-04-21' AND DATE '2025-04-27';
SELECT * FROM books WHERE returned_date > (CURRENT_DATE - INTERVAL '7 days');
SELECT * FROM users WHERE created_at < (CURRENT_DATE - INTERVAL '7 days');
Last month:
WHERE o.delivery_date >= date_trunc('month', CURRENT_DATE - INTERVAL '1 month') AND o.delivery_date < date_trunc('month', CURRENT_DATE)
SELECT ROUND(your_column::numeric, 2) AS rounded_value FROM your_table;
SELECT * FROM company WHERE name IN ('a', 'steeple', 'the');
SELECT * FROM document WHERE accessing_user_ids @> ARRAY['4601ab73-d742-429e-b8e3-ba349725e5f5']::uuid[]
SELECT * FROM company LIMIT 10 OFFSET 30;
ORDER BY field_name ASC/DESC NULLS FIRST/LAST
SELECT COALESCE(phone_number, 'No Phone') AS phone_number FROM employees;
| JOIN Type | Includes Matching Rows (from both tables) | Includes Unmatched Rows (Left Table) | Includes Unmatched Rows (Right Table) |
|---|---|---|---|
| INNER JOIN (or just JOIN) | ✅ Yes | ❌ No | ❌ No |
| LEFT JOIN | ✅ Yes | ✅ Yes | ❌ No |
| RIGHT JOIN | ✅ Yes | ❌ No | ✅ Yes |
| FULL OUTER JOIN | ✅ Yes | ✅ Yes | ✅ Yes |
Examples:
SELECT * FROM weather
LEFT JOIN city ON (weather.city = city.name);
SELECT company.id, company.name, person.name
FROM company
LEFT JOIN company_person ON (company_person.company_id = company.id)
LEFT JOIN person ON (person.id = company_person.person_id)
ORDER BY company.name;
Note: LEFT refers to the left table in ON statement:
SELECT * FROM weather LEFT OUTER JOIN city ON (weather.city = city.name);
SELECT domain.id, name, avg(sai) AS avg_sai FROM domain LEFT OUTER JOIN domain_update ON (domain.id = domain_update.domain_id) GROUP BY domain.id;
Lateral join:
SELECT company.id, company.name, person.id, person.name
FROM company
LEFT JOIN LATERAL (
SELECT id, name
FROM person
WHERE company_id=company.id
LIMIT 1
) person ON TRUE;
-- Lowest/Highest
CONCAT(LEAST(from_city, to_city), ' ↔ ', GREATEST(from_city, to_city)) AS journey,
CASE
WHEN condition1 THEN result1
WHEN conditionN THEN resultN
ELSE result
END;
as part of SELECT:
(CASE WHEN user.id IS NOT NULL THEN user_profile.name ELSE null END) AS user_name
(CASE WHEN username IS NOT NULL THEN username ELSE CAST(article.user_id AS varchar) END) AS user
INITCAP(CASE WHEN product.name ILIKE brand.name || '%' THEN product.name ELSE CONCAT(brand.name, ' ', product.name) END) AS product_name
Update with RANDOM():
UPDATE "order" SET owner_id = (CASE WHEN RANDOM() < 0.5 THEN 21 ELSE 12 END);
SELECT * FROM (
SELECT DISTINCT ON (person.id)
person.*,
title
FROM person
) subquery
WHERE title='CEO';
Note: column types must match in the same order.
SELECT * FROM (
(
SELECT font.id, name, slug, category_id
FROM similar_font
LEFT JOIN font ON (similar_font.font2_id = font.id)
WHERE font1_id = 1643
)
UNION
(
SELECT font.id, name, slug, category_id
FROM similar_font
LEFT JOIN font ON (similar_font.font1_id = font.id)
WHERE font2_id = 1643
)
) AS combined_query
ORDER BY name;
COUNT(DISTINCT(field))
Example:
SELECT
company.*,
COUNT(DISTINCT(company_person.person_id)) AS person_count
FROM company
LEFT JOIN company_person ON (company_person.company_id = company.id)
GROUP BY company.id;
SELECT REPLACE(column_name, 'search_string', 'replace_string') FROM table_name;
STRING_AGG(DISTINCT(category.name), ',') AS category_names
Simpler concatenation
SELECT CONCAT('SQL', ' is', ' fun!') as longer_string;
ARRAY_AGG(category.name) AS category_names
ARRAY_AGG(DISTINCT(category.name)) AS unique_category_names
WITH RECURSIVE category_tree AS (
-- Anchor member: starting point
SELECT id, name, parent_category_id
FROM category
WHERE id = 22 -- <- Change starting category ID here
UNION ALL
-- Recursive member: find parent categories recursively
SELECT c.id, c.name, c.parent_category_id
FROM category c
JOIN category_tree ct ON c.id = ct.parent_category_id
)
-- Select all parent categories, including the starting point
SELECT * FROM category_tree;
SELECT
TO_CHAR(created_date, 'IW') AS period_name,
COUNT(*) AS total_orders
FROM
"order"
WHERE
(selected_owner_id IS NULL OR selected_owner_id = "order".owner_id)
AND created_date >= start_date
AND created_date <= end_date
GROUP BY
period_name
ORDER BY
period_name;
INSERT INTO domain (name, site_count)
VALUES ('indiska.se', 5) RETURNING id;
Multiple values:
INSERT INTO domain (name, count)
VALUES ('domain1.se', 2), ('domain2.se', 3);
INSERT INTO "${tableName}" (${keyFieldNames}, ${otherFieldNames.join(', ')})
VALUES (${allFieldValues.join(', ')})
ON CONFLICT (${keyFieldNames})
DO UPDATE SET ${otherFieldNames.map(fieldName => `${fieldName} = EXCLUDED.${fieldName}`).join(', ')};
UPDATE domain
SET
content_last_update = '2019-01-01 12:00',
content_previous_update = null
WHERE id = 1;
DELETE FROM domain WHERE name = 'formomiljo.se';
SELECT
CONCAT(tables.table_schema, '.', tables.table_name) as schema_and_table
FROM information_schema.tables tables
WHERE
tables.table_type = 'BASE TABLE' -- Exclude views
AND tables.table_schema IN ('public', 'basejump', 'auth')
-- AND tables.table_name ILIKE 'account%' -- NOTE: change here to see other tables
ORDER BY tables.table_schema ASC, tables.table_name ASC;
With columns:
SELECT
CONCAT(columns.table_schema, '.', columns.table_name) as schema_and_table,
columns.column_name,
columns.data_type as column_data_type
-- columns.character_maximum_length,
-- columns.is_nullable,
-- columns.column_default
FROM information_schema.columns columns
JOIN information_schema.tables tables
ON columns.table_name = tables.table_name
AND columns.table_schema = tables.table_schema
WHERE tables.table_type = 'BASE TABLE' -- Exclude views
AND columns.table_schema IN ('public', 'basejump', 'auth')
-- AND columns.table_name ILIKE 'account%' -- NOTE: change here to see other tables
ORDER BY columns.table_schema DESC, columns.table_name ASC;
Dump all tables:
export POSTGRES_DB_URL="postgres://USER:PASSWORD@HOST:PORT/DBNAME"; pg_dump "$POSTGRES_DB_URL" --schema-only --no-owner --no-privileges --schema=public > schema.sql
CREATE TABLE person (
id serial,
name varchar(128),
date_created timestamptz DEFAULT now(),
PRIMARY KEY (id),
UNIQUE (name)
);
CREATE TABLE company_person (
company_id integer REFERENCES "company"(id) ON DELETE CASCADE,
person_id integer REFERENCES "person"(id) ON DELETE CASCADE
);
CREATE UNIQUE INDEX company_person_unique_idx ON company_person(company_id, person_id);
TYPE/ENUM:
CREATE TYPE project_status AS ENUM (
'not-started',
'in-progress',
'in-review',
'completed'
);
CREATE TABLE project (
status project_status NOT NULL
);
ALTER TABLE project
ADD COLUMN status project_status NOT NULL DEFAULT 'not-started';
DOMAIN/CHECK:
CREATE DOMAIN valid_period_months AS integer CHECK (VALUE IN (1, 3, 6, 12));
CREATE TABLE my_table (
period valid_period_months
);
CREATE TABLE flexi_date (
id SERIAL PRIMARY KEY,
year SMALLINT NOT NULL CHECK (year >= 1970 AND year <= 2300),
month SMALLINT CHECK (month >= 1 AND month <= 12),
day SMALLINT CHECK (day >= 1 AND day <= 31),
quarter SMALLINT CHECK (quarter >= 1 AND quarter <= 4)
);
ALTER TABLE person
ADD COLUMN company_id integer NOT NULL REFERENCES company(id) ON DELETE CASCADE;
Remove:
ALTER TABLE domain
DROP COLUMN "change_fraction";
DROP TABLE person;
If delete Company, then delete Person too:
CREATE TABLE company(
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE person(
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL
company_id INT NOT NULL,
CONSTRAINT fk_person_company_id FOREIGN KEY (company_id) REFERENCES company (id) ON DELETE CASCADE
);
Modify existing table:
ALTER TABLE "domain_update" ADD FOREIGN KEY ("domain_update_domain_id_fkey") REFERENCES "domain"("id") ON DELETE CASCADE;
ALTER TABLE person ADD CONSTRAINT fk_person_company_id FOREIGN KEY (company_id) REFERENCES company (id) ON DELETE CASCADE;
-- Find tables that reference FOREIGN KEY accounts.id
SELECT
n.nspname AS referencing_schema,
conrelid::regclass AS referencing_table,
a.attname AS referencing_column
FROM pg_constraint c
JOIN pg_class t ON c.conrelid = t.oid
JOIN pg_namespace n ON t.relnamespace = n.oid
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(c.conkey)
JOIN pg_class tf ON c.confrelid = tf.oid
JOIN pg_attribute af ON af.attrelid = tf.oid AND af.attnum = ANY(c.confkey)
WHERE c.contype = 'f' -- foreign key
AND tf.relname = 'accounts' -- table name
AND af.attname = 'id' -- table field
ORDER BY referencing_schema, referencing_table, referencing_column;
CREATE UNIQUE INDEX event_unique_uuid ON event (uuid);
CREATE UNIQUE INDEX company_person_unique_idx ON company_person(company_id, person_id);
CREATE [MATERIALIZED] VIEW my_view AS (
your query here
)
CREATE OR REPLACE VIEW my_view AS (
your query here
)
Refresh materialized view (view with stored results):
REFRESH MATERIALIZED VIEW my_view
Delete view:
DROP [MATERIALIZED] VIEW IF EXISTS my_view;
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;
In SQL:
CREATE OR REPLACE FUNCTION my_function(name text)
RETURNS TEXT
LANGUAGE plpgsql -- or 'sql'
AS $$
SELECT 'Hello World!', name;
$$;
Executing the function from SQL:
SELECT * FROM my_function('Sam Lowry');
View a function:
SELECT pg_get_functiondef('my_function'::regproc);
In psql: \df+ my_function
List all functions:
SELECT
routine_schema AS schema,
routines.routine_name AS name,
ARRAY_AGG(parameters.parameter_name ORDER BY parameters.ordinal_position) AS parameter_names,
ARRAY_AGG(parameters.data_type ORDER BY parameters.ordinal_position) AS parameter_types,
routines.data_type AS return_type
FROM information_schema.routines
LEFT JOIN information_schema.parameters ON routines.specific_name = parameters.specific_name
WHERE routine_type = 'FUNCTION'
AND parameters.parameter_mode = 'IN'
AND routine_schema = 'public'
-- AND routines.routine_name ILIKE '%order%'
GROUP BY routine_schema, routines.routine_name, routines.data_type
ORDER BY routines.routine_name;
Delete a function:
DROP FUNCTION my_function;
Example: return SETOF
CREATE OR REPLACE FUNCTION get_planets()
RETURNS SETOF planets
LANGUAGE plpgsql
AS $$
SELECT * FROM planets;
$$;
Example with custom RETURNS TABLE definition:
CREATE OR REPLACE FUNCTION public.get_order(_orderid integer)
RETURNS TABLE (
orderid integer,
transportername text,
orderednumberofitems decimal
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN query
SELECT
orderid,
transportername,
orderednumberofitems
FROM orders
WHERE orderid = _orderid;
END;
$$;
Example: add_geometry:
CREATE OR REPLACE FUNCTION add_geometry (location_name varchar, lon float, lat float)
RETURNS SETOF geometries
LANGUAGE plpgsql
AS $
DECLARE
return_record geometries%rowtype;
BEGIN
INSERT INTO geometries(location_name, geom)
VALUES (location_name, ST_SETSRID(ST_MAKEPOINT(lon, lat), 4326))
RETURNING *
INTO return_record;
RETURN NEXT return_record;
END
$;
Example: app.id_generator:
CREATE OR REPLACE FUNCTION app.id_generator(OUT result bigint)
RETURNS bigint
LANGUAGE plpgsql
AS $$
DECLARE
our_epoch bigint := 1111111111111;
seq_id bigint;
now_millis bigint;
-- the id of this DB shard, must be set for each
-- schema shard you have - you could pass this as a parameter too
shard_id int := 1;
BEGIN
SELECT nextval('app.global_id_sequence') % 1024 INTO seq_id;
SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000) INTO now_millis;
result := (now_millis - our_epoch) << 23;
result := result | (shard_id << 10);
result := result | (seq_id);
END;
$$;
CREATE TEMPORARY TABLE temp_order AS
SELECT * FROM public."order"
WHERE delivery_date = '2025-01-01';
RAISE NOTICE 'Inserting for zipcode_id % and district_node_id %', NEW.from_zipcode_id, NEW.to_district_node_id;
In seed file:
DO $$ BEGIN RAISE NOTICE '** Notice 01'; END $$;
Levels (in order of severity):
- RAISE DEBUG – very detailed, usually suppressed unless debugging
- RAISE NOTICE – info messages
- RAISE WARNING – something might be wrong
- RAISE EXCEPTION – throws an actual error
Only RAISE EXCEPTION interrupts the function, the others just print messages to the client or logs.
BEGIN
-- do something
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Update failed: %', SQLERRM;
END;
-- Create new
CREATE OR REPLACE FUNCTION add_account_category_user()
RETURNS TRIGGER AS $$
BEGIN
-- Insert the corresponding row into account_category_user
INSERT INTO public.account_category_user (account_id, category_id, user_id, account_role)
SELECT
NEW.account_id,
NEW.category_id,
a.primary_owner_user_id,
'owner'::public.account_role
FROM
basejump.accounts a
WHERE
a.id = NEW.account_id
ON CONFLICT (account_id, category_id, user_id) DO NOTHING;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_add_account_category_user
AFTER INSERT ON public.account_category
FOR EACH ROW
EXECUTE FUNCTION add_account_category_user();
-- Cleanup trigger: delete account_category_user rows when account_category is deleted
CREATE OR REPLACE FUNCTION delete_account_category_user_trigger()
RETURNS TRIGGER AS $$
BEGIN
-- Delete the corresponding rows from account_category_user
DELETE FROM public.account_category_user
WHERE account_id = OLD.account_id
AND category_id = OLD.category_id;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_delete_account_category_user
AFTER DELETE ON public.account_category
FOR EACH ROW
EXECUTE FUNCTION delete_account_category_user_trigger();
DO $$
DECLARE
v_count INTEGER;
r RECORD;
BEGIN
-- add code here:
SELECT COUNT(DISTINCT id) INTO v_count FROM company;
RAISE NOTICE 'Count: % rows', v_count;
BEGIN
-- do something
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Update failed: %', SQLERRM;
END;
END $$;
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public';
Move to another schema:
ALTER TABLE public.my_table
SET SCHEMA company.departments;
Set timeout for just the current block or function:
SET LOCAL statement_timeout = '2min'; -- or '5000ms', '30s', etc.
Set timeout for just the current session:
SET statement_timeout = '2min';
Set timeout globally (affects all sessions):
In postgresql.conf:
statement_timeout = '2min'
Then reload PostgreSQL:
SELECT pg_reload_conf();
Set for a user or role:
ALTER ROLE myuser SET statement_timeout = '2min';
SELECT current_user;
See permissions:
SELECT table_name, grantee, privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'my_table';
Grant permissions:
GRANT DELETE ON TABLE my_table TO anon;
set role authenticated;
select * from my_table;
Is RLS enabled?
SELECT relname, relrowsecurity
FROM pg_class
WHERE relname = 'my_table';
List RLS policies:
SELECT policyname, cmd, qual, with_check
FROM pg_policies
WHERE schemaname = 'public' AND tablename = 'my_table';
Create:
CREATE POLICY "Users can view teams they created" ON public.teams
FOR SELECT USING (auth.uid() = created_by);
Delete:
DROP POLICY IF EXISTS "Users can view teams they created" ON public.team_members;
pg_dump mydatabase > mydatabase_dump.sql
PGPASSWORD="your_password" pg_dump -U username -h localhost -p 5432 -t public.tablename mydatabase > tablename_dump.sql
pg_dump --no-owner --no-acl --data-only --inserts -d mydatabase -t public.tablename > tablename_dump.sql
One table INSERT:
pg_dump -h localhost -p 54332 -U postgres -d postgres -t tablename -F p --column-inserts -f tablename_dump.sql
Restore:
psql -U [username] -h [hostname] -p [port] -d [destination_database] < [dumpfile.sql]
mysql -p -e "CREATE DATABASE yourdatabase;"
mysql -u username -p -e "CREATE DATABASE yourdatabase;"
mysql -u username -p yourdatabase < mydatabase_dump.sql
ALTER TABLE company_person
ADD CONSTRAINT unique_company_person UNIQUE (company_id, person_id);
SHOW CREATE VIEW view_name;
CREATE OR REPLACE VIEW view_name AS
SELECT...
.exit
http://www.sqlite.org/datatype3.html
Each value stored in an SQLite database (or manipulated by the database engine) has one of the following storage classes:
NULL: The value is a NULL value.INTEGER: The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude of the value.REAL: The value is a floating point value, stored as an 8-byte IEEE floating point number.TEXT: The value is a text string, stored using the database encoding (UTF-8, UTF-16BE or UTF-16LE).BLOB: The value is a blob of data, stored exactly as it was input.
.schema tracks
.show
.separator , // or \t
.import top_30.csv tracks
.dump ?TABLE? ...: Dump the database in an SQL text format
.import FILE TABLE: Import data from FILE into TABLE