Sequelize: joining table on a subquery - postgresql

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.

Related

PostgreSQL Join with special condition

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";

Postgresql: Updating with two inner joins [MySQL to PostgreSQL]

In MySQL it's possible to do something like this:
update
table_a A
inner join
table_b B
on
A.field_five = B.field_five
inner join
table_c C
on
B.field_one = C.field_one and A.field_two = C.field_two
set A.field_three = C.field_four
I have tried to construct the same query in PostgreSQL like this:
update table_a A
set A.field_three = C.field_four
from table_b B
inner join table_c C
on
B.agency_id = C.agency_id and A.field_two = C.field_two
where
A.field_five = B.field_five
I get the following error:
ERROR: invalid reference to FROM-clause entry for table "a"
I'm using PostgreSQL 11. What is the correct way to do this query in postgres?
don't specify what table to update in "set" and move "A.field_two = C.field_two" to the where clause
update table_a A
set field_three = C.field_four
from table_b B
inner join table_c C
on
B.agency_id = C.agency_id
where
A.field_five = B.field_five
and A.field_two = C.field_two
https://www.db-fiddle.com/f/mipu88sd4JDar25TtvQCQJ/1
Youl could rewrite it using CTE:
WITH cte AS (
SELECT c.*, b.field_five
FROM table_b B
JOIN table_c C
ON B.agency_id = C.agency_id
)
UPDATE table_a A
SET field_three = C.field_four
FROM cte c
WHERE A.field_five = c.field_five
AND A.field_two = c.field_two;
db<>fiddle demo

inner query without FROM

I made a mistake when writing the query, I wrote a subquery without a FROM clause:
select * from foo where id in (select id where type 'mm')
I lost half a day to find a mistake because it worked!
I checked the documentation but I did not find any information why ...
It is more interesting:
select * from abc a
inner join abc b on b.id = a.id
where a.id in (select id from (select a.id, row_number () over () lp where b.name = 'abc') x where lp = 1);
http://sqlfiddle.com/#!15/4bb29/12
Can someone explain how it works?
Your first query will certainly not work as it is.
To understand your second query, keep in mind that
A SELECT without a FROM clause is like as if there is a FROM clause with a table that has no column, but one row.
You can reference columns from the outer query in the subquery.
Here is an attempt to explain your query:
SELECT * FROM abc a
/* ok, now we have a table with alias "a" */
INNER JOIN abc b ON b.id = a.id
/* now we also have a table with alias "b" */
WHERE a.id IN
(SELECT id
FROM (SELECT a.id,
/* this will count the one "artificial" row */
row_number() OVER () lp
/* Here you reference the table with alias "b" above.
This is constant as far as the subquery is concerned,
so if it is not TRUE, the subquery will return an
empty result */
WHERE b.name = 'abc') x
/* this is always true, since there is only one line in
the above subquery */
WHERE lp = 1);

How to aggregate calculation in SQL Server?

I have a following script to get the total unit but it gives me an error
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Do I need to calculate SUM(ta.Qty) outside the main table?
SELECT
ta.ProductName
, SUM(ta.Total)
, SUM(SUM(ta.Qty) * ta.Unit)
FROM
tableA tA
INNER JOIN
tableB tB on tA.ID = tb.TableAID
INNER JOIN
tableC tc on ta.ID = tc.TableAID
INNER JOIN
tableD td on td.ID = tb.TableBID
GROUP BY
ta.ProductName
Here is a query in the AdventureWorks database that produces the same error (but might make some sense):
SELECT v.Name AS Vendor, SUM(SUM(p.ListPrice*d.OrderQty)+h.Freight)
FROM Production.Product p
INNER JOIN Purchasing.PurchaseOrderDetail d ON p.ProductID = d.ProductID
INNER JOIN Purchasing.PurchaseOrderHeader h ON h.PurchaseOrderID = d.PurchaseOrderID
INNER JOIN Purchasing.Vendor v ON v.BusinessEntityID = h.VendorID
GROUP BY v.Name
And here are two ways that I could rewrite that query to avoid the error:
SELECT v.Name AS Vendor, SUM(x.TotalAmount+h.Freight)
FROM (
SELECT PurchaseOrderID, SUM(p.ListPrice*d.OrderQty) AS TotalAmount
FROM Production.Product p
INNER JOIN Purchasing.PurchaseOrderDetail d ON p.ProductID = d.ProductID
GROUP BY PurchaseOrderID
) x
INNER JOIN Purchasing.PurchaseOrderHeader h ON h.PurchaseOrderID = x.PurchaseOrderID
INNER JOIN Purchasing.Vendor v ON v.BusinessEntityID = h.VendorID
GROUP BY v.Name
SELECT v.Name AS Vendor, SUM(x.TotalAmount+h.Freight)
FROM Purchasing.PurchaseOrderHeader h
INNER JOIN Purchasing.Vendor v ON v.BusinessEntityID = h.VendorID
CROSS APPLY (
SELECT SUM(p.ListPrice*d.OrderQty) AS TotalAmount
FROM Production.Product p
INNER JOIN Purchasing.PurchaseOrderDetail d ON p.ProductID = d.ProductID
WHERE d.PurchaseOrderID=h.PurchaseOrderID
) x
GROUP BY v.Name
The first query uses derived tables and the second one uses CROSS APPLY.

INNER JOIN in EF 4

i have 2 tables master and details,
in EF 4 i want to write a query to retrieve a data like this t-sql
SELECT Table1.Table1ID, Table1.A, Table2.Table2ID, Table2.B
FROM Table1 INNER JOIN
Table2 ON Table1.Table1ID = Table2.Table1Id
i use this :
using(var context =new context())
{
var p = (from i in context.Table1.Include("Table2") select i);
}
but it returns rows in table1 how can i change it to retrieve rows in table2 and have my join?
thanks
I think you are looking for this:
var query = from a in context.Table1
join b in context.Table2 on a.Table1ID equals b.Table1Id
select new
{
a.Table1ID,
a.A,
b.Table2ID,
b.B,
};