How to use Lateral joins with TypeORM for Postgres db? - postgresql

I have a postgres query with 5 joins which was taking more than 10 secs to execute. I re-wrote the query with lateral join concept and now it executes in less than 1 sec. I want to write that query in TypeORM and didn't find any ways to do it. Any help is appreciated.
This is the query that needs to be converted to TypeORM
FROM "institution" "i"
INNER JOIN "financial_account" "fa" ON "fa"."institutionId"="i"."id"
left join (
select h1.*
from holding as h1
inner join (
select cast(max(h3.holding_date) as DATE) holding_date,h3."accountId"
From "holding" as h3
group by h3."accountId"
) as h2 on h2."accountId" = h1."accountId" and h2."holding_date" = cast(h1."holding_date" as date)
) "h" on "h"."accountId" = "fa".id
LEFT JOIN "securities" "sec" ON "sec"."id"="h"."securityId"
LEFT JOIN "symbol" "sym" ON "sym"."id"="sec"."symbolId" AND "sym"."trRIC"="sec"."symbolTrRIC"
where "i".af_user_id='1234'
ORDER BY "h".institution_value desc;

Related

Transact SQL ON EXISTS statement

I've got a Transact SQL problem which I don't understand.
I have 2 tables tblMedewerker2 and tblMedewerker3.
tblMedewerker2 has got the following values for employeenumber :129, 143,144,145,146,147,169.
tblMedewerker3 has got the following values for employeenumber: 129, 143,144,145,146,147, 166,167,168.
They contain 7 respectively 9 rows, so the values are unique.
The following query yields 63 rows :
select
a.employeenumber as emp_a
, b.employeenumber as emp_b
, isnull(a.employeenumber, b.employeenumber) as single_employeenumber
from tblMedewerker2 a
full join
tblMedewerker3 b
on exists
(
select a.employeenumber from tblMedewerker2
union
select b.employeenumber from tblmedewerker3
)
whereas this query yields 10 rows:
select
a.employeenumber as emp_a
, b.employeenumber as emp_b
, isnull(a.employeenumber, b.employeenumber) as single_employeenumber
from tblMedewerker2 a
full join
tblMedewerker3 b
on exists
(
select a.employeenumber from tblMedewerker2
intersect
select b.employeenumber from tblmedewerker3
)
Why would the first query turn the SQL into some sort of CROSS JOIN ?
I would say the exists just gives back a TRUE or a FALSE. So why the difference in numbers of records in both queries ?
Thanks !
Rgds
BB
It comes down to an how all JOINs work. Let's think about a simple INNER JOIN
SELECT a.id, b.id
FROM
a
INNER JOIN
b
ON a.id = b.id
This is saying "Compare every row to every row in the other table. When the ON condition is true, include the rows joined together in the result"
Now consider the following valid query:
SELECT a.id, b.id
FROM
a
INNER JOIN
b
ON 1==1
Again, the way it works is as described above. "Compare every row to every row in the other table. When the ON condition is true, include the rows joined together in the result". In this case the ON condition is true for all the comparisons.
So if the left table had 7 rows and the right table has 9, you'll get 63 rows. (I put it in a SQL Fiddle for you here to see for yourself: http://sqlfiddle.com/#!18/87097/17)
Your ON EXISTS statement in your first query is always going to be true, since any row in the tables you are joining can be found in the UNION. Its very similar to my 1==1 example above. The fact that it's a FULL JOIN in the first query doesn't matter. If it's a LEFT JOIN or INNER JOIN or FULL JOIN it will return 63 rows.
In your second query the ON condition is only true in a limited set of circumstances: When the row being evaluated happens to be in the intersection of both tables.
As a sidenote. Your second query can be simplified to a usual ON clause comparing the employeeNumbers. This is because the ON clause is really taking the intersection of both tables. You can write your second query as:
select
a.employeenumber as emp_a
, b.employeenumber as emp_b
, isnull(a.employeenumber, b.employeenumber) as single_employeenumber
from tblMedewerker2 a
full join
tblMedewerker3 b
on a.employeeNumber = b.employeeNumner
As mentioned in my comment above another solution (rather than an answer to cartesian products and set intersection part of your question) might be based on a different approach - this is just sketched out and not tested (it's late here and I'm tired):
Generate a CTE of employee IDs and LEFT JOIN this to each table
WITH EmployeeNumbers AS
SELECT DISTINCT employeenumber
FROM
(SELECT employeenumber FROM tblMedewerker2
UNION ALL
SELECT employeenumber FROM tblMedewerker2
) AS p
SELECT
t2.employeenumber AS empA,
t3.employeenumber AS empB,
ISNULL(t2.employeenumber, t3.employeenumber) AS single_employeenumber
-- an alternative to the above line
-- EN.employeenumber AS single_employeenumber
FROM
EmployeeNumbers AS EN
LEFT JOIN
tblMedewerker2 AS T2 ON EN.employeenumber = T2.employeenumber
LEFT JOIN
tblMedewerker3 AS T2 ON EN.employeenumber = T2.employeenumber

Postgresql query deletes all rows

I wrote a simple delete query in a PostgreSQL function with using clause, left join and a where clause. But the query does not take the where condition in consideration. It deletes all rows.
I wrote two types of query both produce same result
Query 1
delete from "StockInfos" using "StockInfos" as si
left outer join "PurchaseOrderInfos" as poi on poi."Id" = si."PurchaseOrderInfoId"
left outer join "ReceivingInfos" as ri on ri."PurchaseOrderInfoId" = poi."Id"
where ri."Id" = (delete_data->>'Id')::bigint;
Query 2
delete from "StockInfos" where exists (
select * from "StockInfos" as si
left join "PurchaseOrderInfos" as poi on poi."Id" = si."PurchaseOrderInfoId"
left outer join "ReceivingInfos" as ri on ri."PurchaseOrderInfoId" = poi."Id"
where ri."Id" = (delete_data->>'Id')::bigint
);
I don understand what is the problem. May anyone tell what is going wrong?
I would rephrase this with a correlated subquery. This makes the logic much cleaner, and should do what you want:
delete from "StockInfos" si
where exists (
select 1
from "PurchaseOrderInfos" poi
inner join "ReceivingInfos" as ri on ri."PurchaseOrderInfoId" = poi."Id"
where
oi."Id" = si."PurchaseOrderInfoId"
and ri."Id" = (si.delete_data->>'Id')::bigint
)

What's the difference between these joins?

What's the difference between
SELECT COUNT(*)
FROM TOOL T
LEFT OUTER JOIN PREVENT_USE P ON T.ID = P.TOOL_ID
WHERE
P.ID IS NULL
and
SELECT COUNT(*)
FROM TOOL T
LEFT OUTER JOIN PREVENT_USE P ON T.ID = P.TOOL_ID AND P.ID IS NULL
?
The bottom query is equivalent to
SELECT COUNT(*)
FROM TOOL T
since it is not limiting the result set but rather producing a joined table with a lot of null fields for the right part of the join.
The first query is a left anti join.

Lateral query syntax

I'm trying to get lateral to work in a Postgres 9.5.3 query.
select b_ci."IdOwner",
ci."MinimumPlaces",
ci."MaximumPlaces",
(select count(*) from "LNK_Stu_CI" lnk
where lnk."FK_CourseInstanceId" = b_ci."Id") as "EnrolledStudents",
from "Course" c
join "DBObjectBases" b_c on c."Id" = b_c."Id"
join "DBObjectBases" b_ci on b_ci."IdOwner" = b_c."Id"
join "CourseInstance" ci on ci."Id" = b_ci."Id",
lateral (select ci."MaximumPlaces" - "EnrolledStudents") x
I want the right-most column to be the result of "MaximumPlaces" - "EnrolledStudents" for that row but am struggling to get it to work. At the moment PG is complaining that "EnrolledStudents" does not exist - which is exactly the point of "lateral", isn't it?
select b_ci."IdOwner",
ci."MinimumPlaces",
ci."MaximumPlaces",
(select count(*) from "LNK_Stu_CI" lnk
where lnk."FK_CourseInstanceId" = b_ci."Id") as "EnrolledStudents",
lateral (select "MaximumPlaces" - "EnrolledStudents") as "x"
from "Course" c
join "DBObjectBases" b_c on c."Id" = b_c."Id"
join "DBObjectBases" b_ci on b_ci."IdOwner" = b_c."Id"
join "CourseInstance" ci on ci."Id" = b_ci."Id"
If I try inlining the lateral clause (shown above) in the select it gets upset too and gives me a syntax error - so where does it go?
Thanks,
Adam.
You are missing the point with LATERAL. It can access columns in tables in the FROM clause, but not aliases defined in SELECT clause.
If you want to access alias defined in SELECT clause, you need to add another query level, either using a subquery in FROM clause (AKA derived table) or using a CTE (Common Table Expression). As CTE in PostgreSQL acts as an optimization fence, I strongly recommend going with subquery in this case, like:
select
-- get all columns on the inner query
t.*,
-- get your new expression based on the ones defined in the inner query
t."MaximumPlaces" - t."EnrolledStudents" AS new_alias
from (
select b_ci."IdOwner",
ci."MinimumPlaces",
ci."MaximumPlaces",
(select count(*) from "LNK_Stu_CI" lnk
where lnk."FK_CourseInstanceId" = b_ci."Id") as "EnrolledStudents",
from "Course" c
join "DBObjectBases" b_c on c."Id" = b_c."Id"
join "DBObjectBases" b_ci on b_ci."IdOwner" = b_c."Id"
join "CourseInstance" ci on ci."Id" = b_ci."Id"
) t

TSQL, join to multiple fields of which one could be NULL

I have a simple query:
SELECT * FROM Products p
LEFT JOIN SomeTable st ON st.SomeId = p.SomeId AND st.SomeOtherId = p.SomeOtherId
So far so good.
But the first join to SomeId can be NULL, In that case the check should be IS NULL, and that's where the join fails. I tried to use a CASE, but can't get that to work also.
Am I missing something simple here?
From Undocumented Query Plans: Equality Comparisons.
SELECT *
FROM Products p
LEFT JOIN SomeTable st
ON st.SomeOtherId = p.SomeOtherId
AND EXISTS (SELECT st.SomeId INTERSECT SELECT p.SomeId)