knex: Postgresql update + joins, from clause missing

Hi,

I hope to rewrite a raw SQL UPDATE/JOINS request to Knex style, but I have an issue with knex : The knex raw request (works well) :

knex.raw("UPDATE barcodes_products B SET bar_code = $6, modify_date = now() " +
                "FROM catalogs_stores S " +
                "  INNER JOIN catalogs C on (S.catalog_id = C.catalog_id AND S.company_id = C.company_id AND C.status = 1) " +
                    "  INNER JOIN catalogsversion R on (R.catalog_id = C.catalog_id AND R.status = 1) " +
                    "  INNER JOIN catalogsversion_products V on (R.catalogversion_id = V.catalogversion_id AND C.catalog_id = R.catalog_id AND V.status = 1) " +
                    "  INNER JOIN products P on (V.product_id = P.product_id AND V.company_id = P.company_id AND P.status = 1) " +
                    "WHERE S.store_id_ref = $1 " +
                    "  AND S.status = 1 " +
                    "  AND C.catalog_id = $2 " +
                    "  AND V.catalogversion_id = $3 " +
                    "  AND R.valid_from < now() " +
                    "  AND (R.valid_until IS NULL OR R.valid_until > now()) " +
                    "  AND P.product_id = $4 " +
                    "  AND B.bar_code = $5 " +
                    "  AND P.purchase_ok = true " +
                    "  AND P.product_id = B.product_id " +
                    "  AND P.company_id = B.company_id " +
                    "  AND B.status = 1",
                    [store, catalog, version, product, barcode_current, barcode_new]
                    )
                    .exec(cb);

The Knex rewrited “style” request :

knex('barcodes_products AS B')
             .from('catalogs_stores AS S')
            .innerJoin('catalogs AS C', function () {
                this.on('S.catalog_id', 'C.catalog_id');
                this.andOn('S.company_id', 'C.company_id');
                this.andOn('C.status', 1);
            })
            .innerJoin('catalogsversion AS R', function () {
                this.on('R.catalog_id', 'C.catalog_id');
                this.andOn('R.status', 1);
            })
            .innerJoin('catalogsversion_products AS V', function () {
                this.on('R.catalogversion_id', 'V.catalogversion_id');
                this.andOn('R.catalog_id', 'V.catalog_id');
                this.andOn('V.status', 1);
            })
            .innerJoin('products AS P', function () {
                this.on('P.product_id', 'V.product_id');
                this.andOn('P.company_id', 'V.company_id');
                this.andOn('P.status', 1);
            })
            .where({
                'S.store_id_ref': store,
                'C.catalog_id': catalog,
                'V.catalogversion_id': version,
                'P.product_id': product,
                'B.barcode': barcode_current
            })
            .andWhere('P.purchase_ok', true)
            .andWhere('B.status', 1)
            .andWhere('P.product_id', 'B.product_id')
            .andWhere('P.company_id', 'B.company_id')
            .andWhere('R.valid_from', '<', 'now()')
            .andWhere(function () {
                this.whereNull('R.valid_until');
                this.orWhere('R.valid_until', '>', 'now()');
            }).update({
                'bar_code': barcode_new,
                'modify_date': 'now()'
            })
            .exec(cb);
        }

Knex generated this SQL statement :

update "catalogs_stores" as "S" set "bar_code" = $1, "modify_date" = $2 where "S"."store_id_ref" = $3 and "C"."catalog_id" = $4 and "V"."catalogversion_id" = $5 and "P"."product_id" = $6 and "B"."barcode" = $7 and "P"."purchase_ok" = $8 and "B"."status" = $9 and "P"."product_id" = $10 and "P"."company_id" = $11 and "R"."valid_from" < $12 and ("R"."valid_until" is null or "R"."valid_until" > $13)

Postgresql respond: missing FROM-clause entry for table "C"

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 2
  • Comments: 16 (6 by maintainers)

Commits related to this issue

Most upvoted comments

@bendrucker @tgriesser Any updates on this issue? This seems to be a pretty common use case, resorting to raw queries makes me doubt the use for knex.

Same problem for me : I need to check a value into db before the update. I’ve hoped i won’t be forced to do 2 queries but with this issue, I have no choice 😢:

knex('table')
      .from('table AS oldValues')
      .where('id', '=', 'id')
      .where('table.id', '=', 'oldValues.id')
      .update(['status', 'newStatus'])
      .returning(['table.*', 'oldValues.status AS oldStatus'])
      .toString();

should return

UPDATE "table" SET "status" = 'newStatus' FROM "table" AS oldValues WHERE "table"."id" = 'id' AND "table"."id" = "oldTable"."id" RETURNING "table".*, "oldValues"."status" AS "oldStatus"