How do we do LEFT JOIN with old syntax? - tsql

How do we do LEFT JOIN with old syntax?
Let's say you have a User table and UserRole table, and you are holding the ID of the UserRole in User table.
Here is the query to retrieve all User's names, and the Role Names with the new notation:
SELECT U.Username, US.[Desc] FROM [User] U
INNER JOIN UserRole US ON U.UserRoleId = US.Id
And here is the old notation:
SELECT U.Username, US.[Desc] FROM [User] U, UserRole US
WHERE U.UserRoleId = US.Id
Now, let's assume that all users don't have a role, the UserRoleId is either 0 or NULL.
Here is the query to retrieve all User's names, and the Role Names with the new notation:
SELECT U.Username, US.[Desc] FROM [User] U
LEFT JOIN UserRole US ON U.UserRoleId = US.Id
Question is: How do we do the same with old syntax, without using the word JOIN?

The operators are *= and =* (depending on which side of the predicate each column is):
SELECT U.Username, US.[Desc]
FROM [User] U, UserRole US
WHERE U.UserRoleId *= US.Id
These have been deprecated since SQL Server 2012 though, since then there is no backward compatibility for a join syntax that was discontinued 24 years ago.
I have no idea why you might want to use this, but here are some reasons to sway you back from the dark side:
Bad habits to kick : using old-style JOINs
Or, if you want an alternative way without joins, or proprietary syntax you can use:
SELECT U.Username, US.[Desc]
FROM [User] U, UserRole US
WHERE U.UserRoleId = US.Id
UNION ALL
SELECT U.Username, NULL
FROM [User] U
WHERE NOT EXISTS (SELECT 1 FROM UserRole US WHERE U.UserRoleId = US.Id);
But once again, why bother, the LEFT JOIN syntax was introduced in ANSI 92, if you can't use it with your database, it is time to change your database vendor, and not your syntax.

Use the PLUS(+) sign :
SELECT U.Username, US.[Desc] FROM [User] U, UserRole US
WHERE U.UserRoleId = US.Id(+)
The + should be placed on any column of the right table of the LEFT JOIN that appears in the WHERE clause.
Though - this is not suggested, this form of syntax usually leads to errors due to the messy code it creates

Related

Postgres: Select multiple but show records where linked field isn't present

I have multiple tables in my Postgres database that are linked by a field called id. My main table, Person is linked to other tables Address, Phone andEmail by id.
This line of code gets information about the person from all tables in the database:
SELECT *
FROM "Person" p, "Address" a
WHERE p.id = a.id
This isn't showing rows where p.id exists, but we don't have an address for that specific person yet (a.id != p.id in any case).
How do I get the select statement to also return fields where a.id is not found to contain p.id?
You want an outer join which can only be done by getting rid of the ancient, outdated and fragile implicit joins in the WHERE clause and use a proper JOIN operator:
select *
from "Person" p
left join "Address" a on p.id = a.id;

Convert LEFT JOIN query to Ecto

I have some queries I need migrate to Ecto and for maintainability reasons, I'd rather not just wrap them in a fragment and call it a day.
They have a lot of LEFT JOINs in them and as I understand from this answer, a left_join in Ecto does a LEFT OUTER JOIN by default. I can't seem to figure out how to specify to Ecto that I want a LEFT INNER JOIN, which is the default behavior for a LEFT JOIN in Postgresql.
To look at a toy example, let's say posts in our database can be either anonymous or they can have a creator. I have a query to get just enough info to make a post preview, but I only want non-anonymous posts to be included:
SELECT
p.id,
p.title,
p.body,
u.name AS creator_name,
u.avatar AS creator_avatar,
FROM posts p
LEFT JOIN users u ON p.creator_id = u.id;
I would translate that into Ecto as:
nonanonymous_posts =
from p in Post,
left_join: u in User, on: p.creator_id == u.id,
select: [p.id, p.title, p.body, u.name, u.avatar]
and Ecto spits out
SELECT
t0."id",
t0."title",
t0."body",
t1."name" AS creator_name,
t1."avatar" AS creator_avatar,
FROM "posts" AS t0
LEFT OUTER JOIN "users" as t1 ON t0."creator_id" = t1."id";
which will give back anonymous posts as well.
There is no such thing as LEFT INNER JOIN. There is only INNER JOIN and LEFT [OUTER] JOIN (OUTER part is optional, as LEFT JOIN must be outer join). So what you want is just :join or :inner_join in your Ecto query.

HQL update column with COUNT

I'm working with Hibernate thus HQL, linked to a PostgreSQL database.
I have a table users and a table teams that are linked with a ManyToMany condition throught the table teams_users.
I'd like to update or select the table team so the property usersCount takes the amount of users belonging to a team.
I do not want to add a #Formula to my Entity Class, because I don't want it to be executed all the time, that's too wastful on big JOIN FETCH query where I do not need the count.
I other words, I'd like to find the HQL equivalent of the following PSQL query
UPDATE teams t
SET users_count = (SELECT COUNT(ut.*)
FROM teams t1
LEFT JOIN teams_users tu
ON t1.id = tu.team_id
WHERE t1.id = t.id
GROUP BY t1.id);
OR
An equivalent of the following
SELECT t.*, count(tu.*) AS users_count
FROM teams t
LEFT JOIN teams_users tu
ON t.id = tu.team_id
GROUP BY t.id;
Unsuccessful tries (to get an idea)
UPDATE Team t SET
t.usersCount = COUNT(t.users)
UPDATE Team t SET
t.usersCount = (SELECT COUNT(t1.users) FROM Team t1 WHERE t1.id = t.id)
SELECT t, count(t.users) AS t.usersCount
FROM Team t
I've found the solution for the UPDATE query.
It simply is
UPDATE Team t
SET t.usersCount = (SELECT COUNT(u) from t.users u)
It makes an extra join on the table users whilst the table teams_users would be enought but well... It works.
If anyone has ths solution for the SELECT one, I'm still curious !

Storing array of IDs and how to correctly unpack them on a select out

This might be partly a design question (new to PostgreSQL) as well.
I have three tables - Users, Groups and User_Group. User_Group represents a combination of 1 user_id being linked to 0..X Group IDs.
The tables are as simple as you think (for now, building out this thing):
User: ID, Name, ....
Group: ID, Name, ...
User_Group: UserID, GroupID int[], ...
So right now, the GroupID field in User_Group is an Integer array. UserID 1 has a value of {1,2,10,19,28} for example.
Goal:
In my UI, I need to represent that list as the group names (ie: {Group1, Group2, Group10, Group19, Group28}).
So, because I am new to PostgreSQL, I'm researching and a couple ideas pop into my mind - unnest, ANY and array replacement. All scream performance issues to me, but I might be wrong (this is the design question, is it smart to store array?)
My query right now:
select
u.*,
g.group_ids
from users u
left join user_group g
on u.id = g.user_id
Piece I'm trying to figure out how to push into:
select ug.group_id
from (select unnest(group_ids) group_id FROM user_group) as ug
left join groups g
on g.id = ug.group_id
This will just result in (obviously) an additional row for each group ID the person is associated with.
Which is the best way to do this?
( Personally I would have a column on Users table as Groups (int array) but your choice is fine too).
It would look like (I used table and field names off the top of my head, slightly modified than yours):
select u.*, g.Name as GroupName
from users u
left join usergroups ug on ug.UserId = u.UserId
left join groups g on g.groupId = ANY( ug.groups );
Update: I might have misunderstood your need. Maybe you meant this:
select u.*,
(select string_agg(g.name,',')
from groups g
inner join usergroups ug on ug.groupId = g.GroupId
where ug.UserId = u.UserID and
g.groupId = ANY( ug.groups )) as Groups
from users u;
There, you have a one-to-many relationship:
User (1)->(*) Groups
This kind of relation doesn't need an intermediary table for the link definition. The one-to-many relation use to have a foreign key in the child table (in this case is Groups).
The result will be:
User: id, name
Group: id, name, user_id
And you can add a constraint to the database as: ALTER TABLE user ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES group;

DB2 Lookup table using two columns of same table

I have a lookup table for institution id, name, address and another table for course details.
In each course record there will be two columns pointing primary and secondary institution ids.
My select query should look like ->
Select course_id,
name,
primary_Institution_id,
Primary_Institution_name,
primary_Institution_address,
Secondary _Institution_id,
Secondary _Institution_name,
Secondary_Institution_address
from [JOIN MAY BE]
where course_id in ('1223','34234','43432')
How to achieve this? I have no control over the tables and I can only select from them and cannot modify their structure.
If you are trying to ask how to do the join, it might look something like this
Select c.course_id,
c.name,
c.primary_Institution_id,
i.name as primary_Institution_name,
i.address as primary_Institution_address
c.secondary_Institution_id
k.name as Secondary _Institution_name,
k.address as Secondary_Institution_address
from courses as c
join institutions as i
on i.id = c.primary_Institution_id
left
join institutions as k
on i.id = c.secondary_Institution_id
where course_id in ('1223','34234','43432')
This assumes that the first institution id is mandatory (never null) so the join is implied as an inner join, but that perhaps the second might be optional (null allowed) so it uses a left join, in case there is nothing to match to.