# Queries across databases > Read a table of another database on the same server as database.table - in SELECT, JOIN, subqueries and INSERT ... SELECT. - Category: Databases & folders - Keywords: cross-database, cross database, other database, another database, database.table, db.table, otherdb.table, reference data, shared tables, copy a table between databases, join two databases, INSERT INTO ... SELECT from another database, dblink, linked server, three-part name, changes only the database it runs in - See also: [Databases and the data folder](databases.md), [Joins](joins.md), [UNION and subqueries](union-subqueries.md), [Users and roles](users-and-roles.md), [Table rights - GRANT ON TABLE](table-rights.md), [The procedure language (execute)](procedure-language.md#execute) One KDB server holds many [databases](databases.md). A query can read a table of **another database** on the same server. Write the database name, a dot and the table name: `refdata.companies`. A real setup: one database `refdata` holds the company list. Every app database reads it from there instead of keeping its own copy. **Example: Company names from a shared reference database** Setup: ```sql CREATE DATABASE refdata; USE refdata; CREATE TABLE companies (symbol STRING PRIMARY KEY, name STRING, sector STRING); INSERT INTO companies VALUES ('CITY', 'City Bank', 'Bank'), ('HYDRO', 'River Hydro', 'Energy'), ('MART', 'Metro Mart', 'Retail'); ``` ```sql CREATE TABLE trades (id LONG PRIMARY KEY, symbol STRING, qty LONG); INSERT INTO trades VALUES (1, 'CITY', 100), (2, 'HYDRO', 40), (3, 'CITY', 25); SELECT t.id, t.symbol, c.name, t.qty FROM trades t JOIN refdata.companies c ON t.symbol = c.symbol ORDER BY t.id; ``` Result: `CREATE TABLE trades (` ```text table 'trades' created ``` `INSERT INTO trades VALUES (1, 'CITY', 100), (2, 'HYDRO', 40), (3, 'CITY', 25)` ```text 3 row(s) inserted ``` `SELECT t.id, t.symbol, c.name, t.qty FROM trades AS t JOIN refdata.companies AS c ON t.symbol = c.sy` | id (LONG) | symbol (STRING) | name (STRING) | qty (LONG) | |---|---|---|---| | 1 | CITY | City Bank | 100 | | 2 | HYDRO | River Hydro | 40 | | 3 | CITY | City Bank | 25 | (3 rows) ## Name a table of another database Syntax: ```sql database.table database.public.table "database"."table" ``` | Written | Means | |---|---| | `companies` | the table in the database you are using | | `refdata.companies` | the table `companies` of the database `refdata` | | `refdata.public.companies` | the same; PostgreSQL apps write the schema `public` | | `demo.companies`, when you use `demo` | your own database: the same as `companies` | - **Notes:** - Database names ignore upper and lower case, like everywhere in KDB. - With no alias, the table name is the alias: `SELECT companies.name FROM refdata.companies`. - It works over HTTP, the PostgreSQL port, `kdb shell`, `kdb sql --data-dir` and the web console. A `Database` opened on its own, without the server's databases, gives an error. ## What works | Statement | Example | |---|---| | `SELECT` | `SELECT * FROM refdata.companies` | | `JOIN`, `LEFT JOIN`, `CROSS JOIN`, `ASOF JOIN` | `FROM trades t JOIN refdata.companies c ON t.symbol = c.symbol` | | subqueries: `IN`, `EXISTS`, a value, `FROM (SELECT ...)` | `WHERE symbol IN (SELECT symbol FROM refdata.companies)` | | `WITH` | `WITH banks AS (SELECT * FROM refdata.companies WHERE sector = 'Bank') ...` | | `INSERT INTO t SELECT ...` | copies rows from the other database into this one | | `CREATE TABLE t AS SELECT ...` | makes a copy in this database | | `UPDATE` / `DELETE` with a subquery | `DELETE FROM trades WHERE symbol NOT IN (SELECT symbol FROM refdata.companies)` | | views, procedures, triggers, [EXECUTE](procedure-language.md#execute) | the other table is read each time they run | **Example: Copy the banks into this database, and count trades of banks** Setup: ```sql CREATE DATABASE refdata; USE refdata; CREATE TABLE companies (symbol STRING PRIMARY KEY, name STRING, sector STRING); INSERT INTO companies VALUES ('CITY', 'City Bank', 'Bank'), ('HYDRO', 'River Hydro', 'Energy'), ('LAKE', 'Lake Bank', 'Bank'); ``` ```sql CREATE TABLE trades (id LONG PRIMARY KEY, symbol STRING, qty LONG); INSERT INTO trades VALUES (1, 'CITY', 100), (2, 'HYDRO', 40), (3, 'LAKE', 25); CREATE TABLE banks (symbol STRING PRIMARY KEY, name STRING); INSERT INTO banks SELECT symbol, name FROM refdata.companies WHERE sector = 'Bank'; SELECT count(*) AS bank_trades, sum(qty) AS bank_qty FROM trades WHERE symbol IN (SELECT symbol FROM refdata.companies WHERE sector = 'Bank'); ``` Result: `CREATE TABLE trades (` ```text table 'trades' created ``` `INSERT INTO trades VALUES (1, 'CITY', 100), (2, 'HYDRO', 40), (3, 'LAKE', 25)` ```text 3 row(s) inserted ``` `CREATE TABLE banks (` ```text table 'banks' created ``` `INSERT INTO banks SELECT symbol, name FROM refdata.companies WHERE sector = 'Bank'` ```text 2 row(s) inserted ``` `SELECT count(*) AS bank_trades, sum(qty) AS bank_qty FROM trades WHERE symbol IN (SELECT symbol FROM` | bank_trades (LONG) | bank_qty (LONG) | |---|---| | 2 | 125 | (1 row) ## Changes stay in your database A statement changes only the database it runs in. `INSERT`, `UPDATE` and `DELETE` of `otherdb.table` are refused. To change the other database, run the statement there (`USE refdata`, or `db=refdata` over HTTP). From there, your database's tables can be read as `yourdb.table`. **Example: Writing into another database is refused** (shows an error) Setup: ```sql CREATE DATABASE refdata; USE refdata; CREATE TABLE companies (symbol STRING PRIMARY KEY, name STRING, sector STRING); ``` ```sql INSERT INTO refdata.companies VALUES ('NEW', 'New Company', 'Bank'); ``` Result: Error: `line 1, column 1: INSERT of table 'refdata.companies' is not allowed: a statement changes only the database it runs in ('demo'). Run it in database 'refdata' (USE refdata), where the tables of 'demo' can be read as demo.