Combine two inner joins? - postgresql

I have the following tables:
dealer
id (PK)
car
- id (PK)
- dealer_id (FK)
notes
- car_id (FK)
- dealer_id (FK)
- user_id (FK)
- is_active Bool
I want to be able to select all dealers that I have active notes for. Current model does not store dealer_id on notes and car_id on notes at once. It's an either or.
I can do the queries separately:
select *
from dealer
inner join notes n on dealer.id = n.dealer_id and n.user_id=${userId} and n.is_active=true
and:
select *
from dealer
inner join car c on dealer.id = c.dealer_id
inner join notes n on c.id = n.car_id and n.user_id=${userId} and n.is_active=true
I tried to simply combine the two inner joins in the queries but then the:
inner join car c on dealer.id = c.dealer_id
would sift out what the first query would give me and so I would not get all the dealers I should be getting.
How can I write one query that gives me all the dealers I have active notes for?
I would like not to get duplicate dealers in the result.

You're almost there. What you want is called UNION:
SELECT n.*
FROM
notes AS n
INNER JOIN dealer AS d ON d.id = n.dealer_id
UNION
SELECT n.*
FROM
notes AS n
INNER JOIN car AS c ON c.id = n.car_id
INNER JOIN dealer AS d ON d.id = c.dealer_id

Related

Postgresql, inner join or subquery or view?

I have the following tables:
user
car
dealer
user_metrics
- user_id (FK) (required)
- dealer_id (FK) (can be null)
- car_id (FK) (can be null)
- saved
- .... other columns
A user can save a car or a dealership, when that happens the user_metrics.saved is set to true and the related car_id or dealership_id is set (car_id and dealership_id are exclusive, only one is set for a row).
I want user A to be able to see all users that have saved the same cars / dealerships.
So, if user A has saved car 1, 2,3 and dealership 5,7, I want to get all users that have saved any of those cars / dealerships.
I thought about inner join on user_metrics, but, I am not sure how to write the entire query that would deliver on this.
What query would allow me to get all users that have saved any of the cars/dealerships a certain user has saved?
If I understand as well maybe the below query solve your problem.
First should find a list of user A has been reserved after that should search which of car or dealer used by another user
with user_saved_data as (
select um.*,
u.name,
...
from user_metrics um
inner join user u
on um.user_id = u.id
where um.saved = true
and u.id = $1 -- User id of user 'A' or any username (Or use other column for create custom condition)
)
select usd.name as current_reserved_user,
u.name as reserved_by_user,
d.*,
c.*
from user_metrics um
inner join user u on um.user_id = u.id
left join user_saved_data usd on usd.dealer_id notnull and usd.dealer_id = um.dealer_id
left join user_saved_data usd on usd.car_id notnull and usd.car_id = um.car_id
left join dealer d on um.dealer_id = d.id
left join car c on um.car_id = c.id

How to find in a many to many relation all the identical values in a column and join the table with other three tables?

I have a many to many relation with three columns, (owner_id,property_id,ownership_perc) and for this table applies (many owners have many properties).
So I would like to find all the owner_id who has many properties (property_id) and connect them with other three tables (Table 1,3,4) in order to get further information for the requested result.
All the tables that I'm using are
Table 1: owner (id_owner,name)
Table 2: owner_property (owner_id,property_id,ownership_perc)
Table 3: property(id_property,building_id)
Table 4: building(id_building,address,region)
So, when I'm trying it like this, the query runs but it returns empty.
SELECT address,region,name
FROM owner_property
JOIN property ON owner_property.property_id = property.id_property
JOIN owner ON owner.id_owner = owner_property.owner_id
JOIN building ON property.building_id=building.id_building
GROUP BY owner_id,address,region,name
HAVING count(owner_id) > 1
ORDER BY owner_id;
Only when I'm trying the code below, it returns the owner_id who has many properties (see image below) but without joining it with the other three tables:
SELECT a.*
FROM owner_property a
JOIN (SELECT owner_id, COUNT(owner_id)
FROM owner_property
GROUP BY owner_id
HAVING COUNT(owner_id)>1) b
ON a.owner_id = b.owner_id
ORDER BY a.owner_id,property_id ASC;
So, is there any suggestion on what I'm doing wrong when I'm joining the tables? Thank you!
This query:
SELECT owner_id
FROM owner_property
GROUP BY owner_id
HAVING COUNT(property_id) > 1
returns all the owner_ids with more than 1 property_ids.
If there is a case of duplicates in the combination of owner_id and property_id then instead of COUNT(property_id) use COUNT(DISTINCT property_id) in the HAVING clause.
So join it to the other tables:
SELECT b.address, b.region, o.name
FROM (
SELECT owner_id
FROM owner_property
GROUP BY owner_id
HAVING COUNT(property_id) > 1
) t
INNER JOIN owner_property op ON op.owner_id = t.owner_id
INNER JOIN property p ON op.property_id = p.id_property
INNER JOIN owner o ON o.id_owner = op.owner_id
INNER JOIN building b ON p.building_id = b.id_building
ORDER BY op.owner_id, op.property_id ASC;
Always qualify the column names with the table name/alias.
You can try to use a correlated subquery that counts the ownerships with EXISTS in the WHERE clause.
SELECT b1.address,
b1.region,
o1.name
FROM owner_property op1
INNER JOIN owner o1
ON o1.id_owner = op1.owner_id
INNER JOIN property p1
ON p1.id_property = op1.property_id
INNER JOIN building b1
ON b1.id_building = p1.building_id
WHERE EXISTS (SELECT ''
FROM owner_property op2
WHERE op2.owner_id = op1.owner_id
HAVING count(*) > 1);

SQL query involving specific count with distinct

I have these tables:
person (id primary key, name)
money (acct primary key, loaner)
loan (id primary key, acct)
How would I create a SQL query that shows for each loaner the names of persons who took more than four loans from that specific loaner? And I want the 4 persons that he loaned to be different with each other.
SELECT
p.id, p.name, m.loaner, COUNT(*)
FROM
person p
INNER JOIN
loan l ON p.id = l.id
INNER JOIN
money m ON l.acct = m.acct
GROUP BY
id, name, lower
HAVING
COUNT(*) = 4
With this query you can find the first part of the question - what should I add?
I would try this out and see what happens :D
SELECT distinct *
FROM person as p_loaner_detailed
WHERE p_loaner_detailed.id in (
SELECT loanerId
FROM (
SELECT p.id, p.name, m.loaner as loanerId
COUNT(*)
FROM person p
INNER JOIN loan l
ON p.id = l.id
INNER JOIN money m
ON l.acct = m.acct
GROUP BY id, name, loanerId
HAVING COUNT(*) > 4
)
)

Postgres: Getting a total related count based on a condition from a related table

My sql-fu is not strong, and I'm sure I'm missing something simple in trying to get this working. I have a fairly standard group of tables:
users
-----
id
name
carts
-----
id
user_id
purchased_at
line_items
----------
id
cart_id
product_id
products
--------
id
permalink
I want to get a total count of purchased carts for each user, if that user has purchased a particular product. That is: if at least one of their purchased carts has a product with a particular permalink, I'd like a count of the total number of purchased carts, regardless of their contents.
The definition a purchased cart is when carts.purchased_at is not null.
select
u.id,
count(c2.*) as purchased_carts
from users u
inner join carts c on u.id = c.user_id
inner join line_items li on c.id = li.cart_id
inner join products p on p.id = li.product_id
left join carts c2 on u.id = c2.user_id
where
c.purchased_at is not NULL
and
c2.purchased_at is not NULL
and
p.permalink = 'product-name'
group by 1
order by 2 desc
The numbers that are coming up for purchased_carts are strangely high, possibly related to the total number of line items multiplied by the number of carts? Maybe? I'm pretty stumped at the result. Any help would be greatly appreciated.
This ought to help:
select u.id,
count(*)
from users u join
carts c on c.user_id = u.id
where c.purchased_at is not NULL and
exists (
select null
from carts c2
join line_items l on l.cart_id = c2.id
join products p on p.id = l.product_id
where c2.user_id = u.id and
c2.purchased_at is not NULL
p.permalink = 'product-name')
group by u.id
order by count(*) desc;
The exists predicate is a semi-join.
bool_or is what you need
select
u.id,
count(distinct c.id) as purchased_carts
from
users u
inner join
carts c on u.id = c.user_id
inner join
line_items li on c.id = li.cart_id
inner join
products p on p.id = li.product_id
where c.purchased_at is not NULL
group by u.id
having bool_or (p.permalink = 'product-name')
order by 2 desc

MS Access INNER JOIN most recent entry

I'm having some trouble trying to get Microsoft Access 2007 to accept my SQL query but it keeps throwing syntax errors at me that don't help me correct the problem.
I have two tables, let's call them Customers and Orders for ease.
I need some customer details, but also a few details from the most recent order. I currently have a query like this:
SELECT c.ID, c.Name, c.Address, o.ID, o.Date, o.TotalPrice
FROM Customers c
INNER JOIN Orders o
ON c.ID = o.CustomerID
AND o.ID = (SELECT TOP 1 ID FROM Orders WHERE CustomerID = c.ID ORDER BY Date DESC)
To me, it appears valid, but Access keeps throwing 'syntax error's at me and when I hit OK, it selects a piece of the SQL text that doesn't even relate to it.
If I take the extra SELECT clause out it works but is obviously not what I need.
Any ideas?
You cannot use AND in that way in MS Access, change it to WHERE. In addition, you have two reserved words in your column (field) names - Name, Date. These should be enclosed in square brackets when not prefixed by a table name or alias, or better, renamed.
SELECT c.ID, c.Name, c.Address, o.ID, o.Date, o.TotalPrice
FROM Customers c
INNER JOIN Orders o
ON c.ID = o.CustomerID
WHERE o.ID = (
SELECT TOP 1 ID FROM Orders
WHERE CustomerID = c.ID ORDER BY [Date] DESC)
I worked out how to do it in Microsoft Access. You INNER JOIN on a pre-sorted sub-query. That way you don't have to do multiple ON conditions which aren't supported.
SELECT c.ID, c.Name, c.Address, o.OrderNo, o.OrderDate, o.TotalPrice
FROM Customers c
INNER JOIN (SELECT * FROM Orders ORDER BY OrderDate DESC) o
ON c.ID = o.CustomerID
How efficient this is another story, but it works...