I have a query that I've written in Prisma. It basically connects 7 tables, each of which only has maybe 2-4 rows. Yes, 2-4 rows, that's it.
The query that Prisma generates can take upwards of 2-3 minutes to run.
When I write the query directly in SQL, it runs in 1ms.
So, the query I write looks like :
SELECT *
FROM rubricCellAssessment
INNER JOIN rubricAssessment ON rubricCellAssessment.rubricAssessmentId = rubricAssessment.id
INNER JOIN rubricCell ON rubricCellAssessment.rubricCellId = rubricCell.id
INNER JOIN criteriaDescriptor ON rubricCell.criteriaDescriptorId = criteriaDescriptor.id
INNER JOIN criteria ON criteriaDescriptor.criteriaId = criteria.id
INNER JOIN skill ON criteria.skillId = skill.id
INNER JOIN user AS student ON rubricAssessment.studentId = student.id
INNER JOIN user AS assessor ON rubricAssessment.assessorId = assessor.id
LEFT JOIN studentContentBase ON rubricAssessment.studentContentBaseId = studentContentBase.id
WHERE student.userTypeId = 1
AND assessor.userTypeId IN (2, 1000, 3)
AND skill.id = 'bd47bfff-760c-4fec-86d2-1063bbd89d63'
AND criteriaDescriptor.criteriaId = criteria.id
AND rubricCell.criteriaDescriptorId = criteriaDescriptor.id;
The query prisma produces looks like this:
select
`lp-mvp`.`RubricCellAssessment`.`id`,
`lp-mvp`.`RubricCellAssessment`.`createdAt`,
`lp-mvp`.`RubricCellAssessment`.`updatedAt`,
`lp-mvp`.`RubricCellAssessment`.`assessmentValue`,
`lp-mvp`.`RubricCellAssessment`.`rubricCellId`,
`lp-mvp`.`RubricCellAssessment`.`rubricAssessmentId`
from
`lp-mvp`.`RubricCellAssessment`
where
((`lp-mvp`.`RubricCellAssessment`.`id`) in (
select
`t0`.`id`
from
`lp-mvp`.`RubricCellAssessment` as `t0`
inner join `lp-mvp`.`RubricAssessment` as `j0` on
(`j0`.`id`) = (`t0`.`rubricAssessmentId`)
where
((`j0`.`id`) in (
select
`t1`.`id`
from
`lp-mvp`.`RubricAssessment` as `t1`
inner join `lp-mvp`.`User` as `j1` on
(`j1`.`id`) = (`t1`.`studentId`)
where
(`j1`.`userTypeId` = 1
and `t1`.`id` is not null))
and `t0`.`id` is not null))
and (`lp-mvp`.`RubricCellAssessment`.`id`) in (
select
`t0`.`id`
from
`lp-mvp`.`RubricCellAssessment` as `t0`
inner join `lp-mvp`.`RubricCell` as `j0` on
(`j0`.`id`) = (`t0`.`rubricCellId`)
where
((`j0`.`id`) in (
select
`t1`.`id`
from
`lp-mvp`.`RubricCell` as `t1`
inner join `lp-mvp`.`CriteriaDescriptor` as `j1` on
(`j1`.`id`) = (`t1`.`criteriaDescriptorId`)
where
((`j1`.`id`) in (
select
`t2`.`id`
from
`lp-mvp`.`CriteriaDescriptor` as `t2`
inner join `lp-mvp`.`Criteria` as `j2` on
(`j2`.`id`) = (`t2`.`criteriaId`)
where
((`j2`.`id`) in (
select
`t3`.`id`
from
`lp-mvp`.`Criteria` as `t3`
inner join `lp-mvp`.`Skill` as `j3` on
(`j3`.`id`) = (`t3`.`skillId`)
where
(`j3`.`id` = "bd47bfff-760c-4fec-86d2-1063bbd89d63"
and `t3`.`id` is not null))
and `t2`.`id` is not null))
and `t1`.`id` is not null))
and `t0`.`id` is not null))
and (`lp-mvp`.`RubricCellAssessment`.`id`) in (
select
`t0`.`id`
from
`lp-mvp`.`RubricCellAssessment` as `t0`
inner join `lp-mvp`.`RubricAssessment` as `j0` on
(`j0`.`id`) = (`t0`.`rubricAssessmentId`)
where
((`j0`.`id`) in (
select
`t1`.`id`
from
`lp-mvp`.`RubricAssessment` as `t1`
inner join `lp-mvp`.`User` as `j1` on
(`j1`.`id`) = (`t1`.`assessorId`)
where
(`j1`.`userTypeId` in (2,1000,3)
and `t1`.`id` is not null))
and `t0`.`id` is not null))
and (`lp-mvp`.`RubricCellAssessment`.`id`) in (
select
`t0`.`id`
from
`lp-mvp`.`RubricCellAssessment` as `t0`
inner join `lp-mvp`.`RubricCell` as `j0` on
(`j0`.`id`) = (`t0`.`rubricCellId`)
where
((`j0`.`id`) in (
select
`t1`.`id`
from
`lp-mvp`.`RubricCell` as `t1`
inner join `lp-mvp`.`CriteriaDescriptor` as `j1` on
(`j1`.`id`) = (`t1`.`criteriaDescriptorId`)
where
((`j1`.`id`) in (
select
`t2`.`id`
from
`lp-mvp`.`CriteriaDescriptor` as `t2`
inner join `lp-mvp`.`Criteria` as `j2` on
(`j2`.`id`) = (`t2`.`criteriaId`)
where
((`j2`.`id`) in (
select
`t3`.`id`
from
`lp-mvp`.`Criteria` as `t3`
inner join `lp-mvp`.`Skill` as `j3` on
(`j3`.`id`) = (`t3`.`skillId`)
where
(`j3`.`id` = "bd47bfff-760c-4fec-86d2-1063bbd89d63"
and `t3`.`id` is not null))
and `t2`.`id` is not null))
and `t1`.`id` is not null))
and `t0`.`id` is not null)))
Is there any way to optimize this (other than use RAWsql?)? I'm surprised Prisma's code generation is this bad, but I'd rather not move away from it at this point if possible.
All help gratefully accepted.
I have this query:
with active_cars as (
select c.id
from car c
inner join dealership d on c.dealer_id = d.id and d.active=true and d.ownerId=${userId}
)
select cd.*
from car_details cd
inner join active_cars ac on cd.car_id = ac.id
where cd.ratings=5;
Then I have query:
with ports_active_cars as (
select c.id
from car c
inner join ports p on c.port_id = p.id and p.active=true and p.ownerId=${userId}
)
select cd.*
from car_details cd
inner join ports_active_cars pac on cd.car_id = pac.id
I'd like to know how I can combine the result of the two queries into one, so I get one result including all car_details records.
I tried this:
with active_cars as (
select c.id
from car c
inner join dealership d on c.dealer_id = d.id and d.active=true and d.ownerId=${userId}
)
select cd.*
from car_details cd
inner join active_cars ac on cd.car_id = ac.id
where cd.ratings=5
union all
with ports_active_cars as (
select c.id
from car c
inner join ports p on c.port_id = p.id and p.active=true and p.ownerId=${userId}
)
select cd.*
from car_details cd
inner join ports_active_cars pac on cd.car_id = pac.id;
but that is wrong, does not run.
Is there a way to combine the two into one result returning all rows of car_details?
You need to define both CTEs at the start of the statement:
with active_cars as (
select c.id
from car c
inner join dealership d
on c.dealer_id = d.id and d.active = true and d.ownerId = ${userId}
),
ports_active_cars as (
select c.id
from car c
inner join ports p
on c.port_id = p.id and p.active=true and p.ownerId = ${userId}
)
select cd.*
from car_details cd
inner join active_cars ac on cd.car_id = ac.id
where cd.ratings = 5
union all
select cd.*
from car_details cd
inner join ports_active_cars pac on cd.car_id = pac.id;
PostgreSQL 11
How to pass o.create_date value into INNER JOIN? I need Max ID before o.create_date
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_invenotry oi on o.id = oi.order_id
LEFT JOIN ax_inventory i on i.id = oi.inventory_id
LEFT JOIN ax_suppliers s on s.id = o.supplier_id
INNER JOIN ax_supplier_price sp ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
INNER JOIN
(
SELECT inventory_id,
max(id) id
FROM ax_supplier_price
WHERE create_date <= o.create_date
GROUP BY inventory_id
) lsp ON (sp.id = lsp.id)
WHERE o.store_id = 13
AND o.supplier_id = 35
GROUP BY o.id, o.create_date
ORDER BY o.id
You could use the LATERAL join mechanism to make it work:
WITH ax_order AS (
SELECT *
FROM (VALUES (1, '2000-1-1'::date, 1, 1)) as x(id, create_date, store_id, supplier_id)
), ax_order_inventory AS (
SELECT *
FROM (VALUES (1, 2, 4)) as x(order_id, inventory_id, quantity)
), ax_supplier_price AS (
SELECT *
FROM (VALUES (1, 2, 1, 10, '1999-12-31'::date)) as x(id, inventory_id, supplier_id, price, create_date)
)
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_inventory oi on o.id = oi.order_id
INNER JOIN ax_supplier_price sp ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
INNER JOIN LATERAL
(
SELECT inventory_id,
max(lsp.id) id
FROM ax_supplier_price lsp
WHERE sp.create_date <= o.create_date
GROUP BY inventory_id
) lsp ON sp.id = lsp.id
GROUP BY o.id, o.create_date
ORDER BY o.id
I deleted some JOINs that were not strictly necessary and mocked your data as well as I could see. Note, however, that you could also use a WHERE clause to find it - which should be more efficient:
WITH ax_order AS (
SELECT *
FROM (VALUES (1, '2000-1-1'::date, 1, 1)) as x(id, create_date, store_id, supplier_id)
),
ax_order_inventory AS (
SELECT *
FROM (VALUES (1, 2, 4)) as x(order_id, inventory_id, quantity)
),
ax_supplier_price AS (
SELECT *
FROM (VALUES (1, 2, 1, 10, '1999-12-31'::date)) as x(id, inventory_id, supplier_id, price, create_date)
)
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_inventory oi on o.id = oi.order_id
INNER JOIN ax_supplier_price sp
ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
WHERE sp.id =
(
-- NOTE: no GROUP BY necessary!
SELECT max(lsp.id) id
FROM ax_supplier_price lsp
WHERE sp.create_date <= o.create_date
AND lsp.inventory_id = sp.inventory_id
)
GROUP BY o.id, o.create_date
ORDER BY o.id
Lets assume we have the following table1:
1 2 3
a x m
a y m
b z m
I want to do an inner join on the table
INNER JOIN tabel2 ON table1.2 = table2.2
Somehow like this, but additional a condition that the value of table1.1 not unique. Thus on table1.1 = b no inner join will occure in this example.
What is the best way to achieve this?
Using a an aggregate in a sub query is how I would do it
SELECT *
FROM table1
JOIN table2
ON table1."2" = table2."2"
JOIN (
SELECT "1"
FROM table1
GROUP BY "1"
HAVING COUNT(*) > 1
) AS sub_q
ON sub_q."1" = table1."1";
Another option might be a cte or temporary table to hold the rows you're joining on
WITH _cte AS
(
SELECT "1"
FROM table1
GROUP BY "1"
HAVING COUNT(*) > 1
)
SELECT *
FROM table1
JOIN table2
ON table1."2" = table2."2"
JOIN _cte AS cte
ON cte."1" = table1."1";
temp table:
CREATE TEMPORARY TABLE _tab
(
"1" varchar
);
INSERT INTO _tab
SELECT "1"
FROM table1
GROUP BY "1"
HAVING COUNT(*) > 1;
SELECT *
FROM table1
JOIN table2
ON table1."2" = table2."2"
JOIN _tab AS tab
ON tab."1" = table1."1";
I am trying to join a table on a subquery, but I don't know how to express it using Sequelize ORM. This is the raw SQL I want to run:
SELECT *
FROM table_a a
LEFT OUTER JOIN (SELECT * FROM table_b b WHERE col = VAL) ON a.id = b.id;
I tried
A.findAll({
include: [
{
model: B,
where: { col: val },
}
]
}).then(...);
but that doesn't get me the query I want. Instead it changes the join to an INNER JOIN, and joins on col = VALUE instead. Is there a way to do a join on the result of a subquery? I am using Postgres if it matters.
Update: After making the following change, the resulting query now uses a LEFT OUTER JOIN as expected:
include: [
{
model: B,
where: { col: val },
required: false,
}
]
However, it is still joining on col = VALUE, the generated query looks like:
SELECT * FROM table_a a
LEFT OUTER JOIN table_b b ON a.id = b.id AND b.col = VALUE;
These 2 queries ARE functionally equivalent:
SELECT * FROM table_a a
LEFT OUTER JOIN (SELECT * FROM table_b b WHERE col = VAL) ON a.id = b.id;
SELECT * FROM table_a a
LEFT OUTER JOIN table_b b ON a.id = b.id AND b.col = VALUE;
There is NO ADVANTAGE from the first one whatsoever. So, if the first one provides the wanted results, so should the second one.