Knex: Join two tables across two different schemas ( One database)

Created on 23 Jul 2016  ·  3Comments  ·  Source: knex/knex

Hello,
How can we implement table join across two different schemas but the same database.
Technically schemas are just logical separation of tables within the same database so while writing a SQL query all we need to is prefix them with schema name.
For example,

select * 
from user_schema.users as users
inner join account_schema.accounts  as accounts
on users.users.id = accounts.user_id

I could probably write below kenx.js. Does that look good ?

knex.from('user_schema.users as users').innerJoin('account_schema.accounts as accounts', 
'users.id', 'accounts.user_id')

But then i saw .withSchema option with knex.js What is the advantage of using that option instead of prefixing the table name with schema. How can I use .withSchema option to join join tables from two different schemas ?

Knex.js Documentation 
------------------------
.withSchema([schemaName]) 
Specifies the schema to be used as prefix of table name.

knex.withSchema('public').select('*').from('users')

Outputs:
select * from `public`.`users`

Most helpful comment

The document says Identifier Syntax, ie, table name, column name, has no place for selecting schema, so if you are doing schemaName.tableName, query might be rendered wrong.

It suggested use .withSchema('schemaName') instead.

But I found .withSchema only work in one schema all over the builder block.

As so far, I have the following temporary sollutins:

  • Do not use .withSchema at all in speasure query, include schema name in table name string.
    This against the document.

  • Use sub-query with .withSchema

    {
        let rows = await knex.withSchema("sandbox1")
            .select('first_name', 'last_name', 'phone', 'site', "sites.name as sname")
            .from('users')
            .leftJoin(
                knex.withSchema('public')
                    .table('sites')
                    .select()
                    .as("sites"),
                "sites.id",
                "users.site")
        console.log(rows)
    }

This way need use .as in sub query.

  • Use .joinRaw()
    {
        let queryBuilder = knex.withSchema("sandbox1")
            .select('first_name', 'last_name', 'phone', 'site', "sites.name as sname")
            .from('users')
            .joinRaw("left join public.sites as sites ON sites.id = users.site", [])
        let sql = queryBuilder.toSQL().toNative()
        let rows = await queryBuilder

        console.log((sql))
        console.log(rows)
    }
  • Use .raw()
    {
        let { rows ,rowCount } = await knex
            .raw('SELECT users.first_name, users.last_name, users.phone, users.site, sites.name as sname FROM sandbox1.users, public.sites WHERE sites.id = users.site;');

        console.log(rows)
    }

This has less benifits to use knex.

  • Use other libarary or ORMs or drivers.

The final power.

All 3 comments

any solution for this one?

The document says Identifier Syntax, ie, table name, column name, has no place for selecting schema, so if you are doing schemaName.tableName, query might be rendered wrong.

It suggested use .withSchema('schemaName') instead.

But I found .withSchema only work in one schema all over the builder block.

As so far, I have the following temporary sollutins:

  • Do not use .withSchema at all in speasure query, include schema name in table name string.
    This against the document.

  • Use sub-query with .withSchema

    {
        let rows = await knex.withSchema("sandbox1")
            .select('first_name', 'last_name', 'phone', 'site', "sites.name as sname")
            .from('users')
            .leftJoin(
                knex.withSchema('public')
                    .table('sites')
                    .select()
                    .as("sites"),
                "sites.id",
                "users.site")
        console.log(rows)
    }

This way need use .as in sub query.

  • Use .joinRaw()
    {
        let queryBuilder = knex.withSchema("sandbox1")
            .select('first_name', 'last_name', 'phone', 'site', "sites.name as sname")
            .from('users')
            .joinRaw("left join public.sites as sites ON sites.id = users.site", [])
        let sql = queryBuilder.toSQL().toNative()
        let rows = await queryBuilder

        console.log((sql))
        console.log(rows)
    }
  • Use .raw()
    {
        let { rows ,rowCount } = await knex
            .raw('SELECT users.first_name, users.last_name, users.phone, users.site, sites.name as sname FROM sandbox1.users, public.sites WHERE sites.id = users.site;');

        console.log(rows)
    }

This has less benifits to use knex.

  • Use other libarary or ORMs or drivers.

The final power.

Adding one more detail to @codinggirl 's answer:

Using joinRaw() you can bind the parameters. Which generates query with an identical syntax all over the query.

    {
        const queryBuilder = knex.withSchema("sandbox1")
            .select('first_name', 'last_name', 'phone', 'site', "sites.name as sname")
            .from('users')
            .joinRaw("left join ?? ON ?? = ??", ["public.sites", "sites.id", "users.site"])
        const sql = queryBuilder.toString()
        console.log(sql)
    }

Note: Positional bindings ? are interpreted as values and ?? are interpreted as identifiers.

Output with bindings on PG:
select "first_name", "last_name", "phone", "site", "sites"."name" as "sname" from "sandbox1"."users" left join "public"."sites" ON "sites"."id" = "users"."site"

Output with bindings on MSSQL:
select [first_name], [last_name], [phone], [site], [sites].[name] as [sname] from [sandbox1].[users] left join [public].[sites] ON [sites].[id] = [users].[site]

Meanwhile, without binding, it would always generate:
select "first_name", "last_name", "phone", "site", "sites"."name" as "sname" from "sandbox1"."users" left join public.sites ON sites.id = users.site

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  ·  3Comments

npow picture npow  ·  3Comments

lanceschi picture lanceschi  ·  3Comments

saurabhghewari picture saurabhghewari  ·  3Comments

nklhrstv picture nklhrstv  ·  3Comments