Select statement using primary key with no primary key - sql

Ok so I have a table for notes in my database and a table for users in my database. Lets say notes table looks like this:
NoteId NoteTitle NoteAuth
--------------------------------
1 TempTitle 254
2 TempTitle2 871
and Users table looks like:
UserId UserName
-------------------
254 Bob
871 Jim
How can I select from the Note table but select the NoteAuth as the UserName from the Users table. Basically how can I use a primary key without a primary key being set up on the table.

SELECT NoteID, NoteTitle, UserName
FROM Notes INNER JOIN Users ON Notes.NoteAuth = Users.UserID
There's no requirement for any keys to exist to use a column in a JOIN.

You can try something like this
SELECT Notes.NoteId, Notes.NoteTitle, Notes.NoteAuth
FROM Notes
INNER JOIN Users ON Notes.NoteAuth = Users.UserId
WHERE Users.UserName = 'Bob'
Edit
Here is a version that returns the user name for a specified note author.
SELECT Users.UserName, Notes.NoteId, Notes.NoteTitle, Notes.NoteAuth
FROM Notes
INNER JOIN Users ON Notes.NoteAuth = Users.UserId
WHERE Notes.NoteAuth = 254

select n.NoteId, n.NoteTitle, n.NoteAuth, u.UserName
from Notes n
inner join User u on n.NoteAuth = u.UserID

The lack of a primary key will cause lack of table integrity. Now you won't be able to create a foreign key between the tables. This means that going forward you will be allowed to create a note with a user that doesn't exist in the Users table.
This won't stop you from
SELECT n.NoteTitle, u.UserName
FROM NoteTable n LEFT JOIN Users u ON n.NoteAuth = u.UserId
That will work in SqlServer.
The problem is is if you have a note that has a NoteAuth that doesn't exist in the users table, you'll end up with a NULL username. Use an ISNULL to replace NULL with something like 'No Username'.
But like I said, there won't be any integrity between the tables.

SELECT U.Username, N.NoteTitle from Notes N, Users U WHERE N.NoteAuth = U.UserId

Related

User with multiple roles and multiple teams database design

I am unable to get my head around this
I want to allow users to have multiple roles and multiple teams and maybe in the future add something else.
What is the most optimal way to design this?
Users
----------
user_id
first name
last name
roles
--------
role_id
user_id (fk)
role_name
teams
-----
team_id
user_id (fk)
team name
something_else
------
selse_id
user_id (fk)
selse_name
and then group everything in one table like this?
user_profile
---------------------
user_id - username - role_name - team_name - selse_name
I don't know if this should be fine or not, because I am thinking it might get complicated when I pass the data to a form on the client side.
Your schema design is similar to how I would do this. Where your question falls apart is in the last bit about grouping everything together.
The schema should be:
create table users (
user_id serial primary key,
first_name text not null,
last_name text not null,
-- other columns here
);
create table roles (
role_id serial primary key,
role_name text not null unique,
-- other columns here
);
create table user_role (
id serial primary key,
user_id int not null references users(user_id),
role_id int not null references roles(role_id),
unique(user_id, role_id)
);
Make the lookup and join tables for teams and something_else similarly.
The tricky part is pulling this data for use in a UI. You will need to aggregate the properties or else you will have multiple rows for each user. For example, if a user has three roles, belongs to two teams, and has four something_else rows, then joining will net you twenty-four rows for that user.
Assuming your UI will be web or some modern toolkit, the best way to retrieve this data would be as json. PostgreSQL can build that json for you:
with aggs as (
select u.user_id, u.first_name, u.last_name,
jsonb_agg(DISTINCT to_jsonb(r)) as roles,
jsonb_agg(DISTINCT to_jsonb(t)) as teams,
jsonb_agg(DISTINCT to_jsonb(s)) as something_else
from users u
left join user_role ur on ur.user_id = u.user_id
left join roles r on r.role_id = ur.role_id
left join user_team ut on ut.user_id = u.user_id
left join teams t on t.team_id = ut.team_id
left join user_something_else us on us.user_id = u.user_id
left join something_else s on s.something_else_id = us.something_else_id
group by u.user_id, u.first_name, u.last_name
)
select to_jsonb(aggs)
from aggs
where user_id = ?
;

SQL Query multi reference to a table

I have two tables Task and User
Task PRIMARY KEY
IdTask
TaskName
IdHandler FOREIGN KEY REFERENCES IdUser
IdCreator FOREIGN KEY REFERENCES IdUser
User
IdUser PRIMARY KEY
Name
How to query with IdHandler and IdCreator reference to IdUser
Expected Result: TaskName, Name(Handler), Name(Creator)
PS: I'm also do not know if I can put Foreign Keys like that, at least SQL Server let me do it.
SELECT TaskName, h.Name [HandlerName], c.Name [CreatorName]
FROM Task t
INNER JOIN User h ON t.IdHandler = h.IdUser
INNER JOIN User c ON t.IdCreator = c.IdUser
Please see below query.
Select
tt.TaskName,
userHandler.Name as 'UserHandler',
userCreator.Name as 'UserCreator'
from
TasKTable tt
left join
User userHandler on userHandler.IdUser = tt.IdHandler
left join
User userCreator on userCreator.IdCreator = tt.IdHandler
select all field from all table
Select
tt.*,
userHandler.*,
userCreator.*
from
TasKTable tt left join
User userHandler on userHandler.IdUser = tt.IdHandler left join
User userCreator on userCreator .IdCreator = tt.IdHandler
You may also check this SQL Tutorial for reference.
Here is an alternative query not using JOINs
select T.NAME_TASK
,(select U1.NAME from USERS U1 where U1.ID_USER = T.ID_HANDLER) as HANDLER
,(select U2.NAME from USERS U2 where U2.ID_USER = T.ID_CREATOR) as CREATOR
from TASKS T
Refer to this db<>fiddle

SQL Server Select from table where primary key does not appear as foreign key in another table

I have 3 tables -
User UserID PK
SecurityGroup SecurityGroupID PK, SecurityGroupName
UserSecurityGroup UserSecurityGroupID, UserID FK, SecurityGroupID FK
I am trying to select the names of the security groups that a user is NOT a part of.
A user can be a member of more than one group.
i.e. I have three security groups: Admin, Moderator, Member
I pass through a UserID. Said user is assigned to the Admin and Moderator groups but is NOT part of the Member group. I'm trying to display "Member".
These are my attempts so far:
Attempt 1 -
select tblSecurityGroup.SecurityGroupName
from tblSecurityGroup
inner join tblUserSecurityGroup
on tblSecurityGroup.SecurityGroupID = tblUserSecurityGroup.SecurityGroupID
inner join tblUser
on tblUserSecurityGroup.UserID = tblUser.UserID
where tblUser.UserID = 1
and tblSecurityGroup.SecurityGroupID not in (tblUserSecurityGroup.SecurityGroupID);
Attempt 2 -
select tblSecurityGroup.SecurityGroupName
from tblSecurityGroup
inner join tblUserSecurityGroup
on tblSecurityGroup.SecurityGroupID = tblUserSecurityGroup.SecurityGroupID
inner join tblUser
on tblUserSecurityGroup.UserID = tblUser.UserID
where tblUser.UserID = 1
and not exists (select tblSecurityGroup.SecurityGroupID
from tblSecurityGroup
where tblUserSecurityGroup.SecurityGroupID = tblSecurityGroup.SecurityGroupID);
Guidance for a nooby student would be most appreciated.
Your question can be answered by a not exists query. Here is one method:
select sg.SecurityGroupName
from tblSecurityGroup sg
where not exists (select 1
from tblUserSecurityGroup usg
where sg.SecurityGroupID = usg.SecurityGroupID and
usg.UserID = 1
);
Note that tblUser is not needed because UserID is in tblUserSecurityGroup.

Selecting rows which do not exist for a specific user

I have 4 tables (Users,Config,Fields,AvailableFields)
User's relevant schema is
UserID uniqueidentifier NOT NULL PRIMARY_KEY
Config's relevant schema is
ConfigID uniqueidentifier NOT NULL PRIMARY KEY
UserID uniqueidentifier NOT NULL FOREIGN KEY (User.UserID)
Field's relevant schema is
FieldID uniqueidentifier NOT NULL PRIMARY KEY
AvailableFieldID uniqueidentifier NOT NULL FOREIGN KEY (AvailableFields.AvailableFieldsID)
ConfigID uniqueidentifier NOT NULL FOREIGN KEY (Config.ConfigID)
AvailableFields relevant schema is
AvailableFieldID uniqueidentifier NOT NULL PRIMARY KEY
I am trying to return all of the Available fields for a specific user which they do not have in their Fields table.
Is there a way to do this with a join?
I cannot see a way as the only link between the template AvailableFields table is AvailableFieldID which is a foreign key inside Fields table.
Yes, use the INNER JOIN function with the Config as the first table and Field as the second table to get all users with a Config entry. Then use RIGHT JOIN to select all the available field entries and leave out users with no available field entry.
Then all of the select with WHERE AvailableFields.AvailableFieldID IS NULL. This joins the table with all results from Field/Config table. Then it selects the users who do not have an AvailableFields entry.
Code:
SELECT *
FROM Config
INNER JOIN Field ON Config.ConfigID = Field.ConfigID
RIGHT JOIN AvailableFields ON AvailableFields.AvailableFieldID = Field.AvailableFieldID
WHERE Field.UserID IS NULL
This will return all entries in AvailableFields that don't have a corresponding Field entry (i.e. No users) .
You need to use combination of INNER JOIN and RIGHT JOIN
SELECT af.AvailableFieldID
from Config C
inner join Field F on F.configid = c.configid
right join AvailableFields af on F.AvailableFieldID = af.AvailableFieldID
where f.AvailableFieldID is null
Use
SELECT AvailableFieldID FROM AvailableFields
WHERE AvailableFieldID NOT IN (
SELECT AvailableFieldID from Field f INNER JOIN Config c ON f.ConfigID = c.ConfigID INNER JOIN UserID u on u.UserID = c.UserID
WHERE UserID = "Your condition")
I hope resolve your problem.
I think the most intuitive way would be to use NOT IN with a subquery:
SELECT * from AvailableField
WHERE AvailableField.AvailableFieldId NOT IN
(SELECT AvailableFieldId FROM Field
INNER JOIN Config ON Config.ConfigId = Field.ConfigId
WHERE Config.UserId = ?)
Where ? is a placeholder for the ID of the user you are interested in.
If you are performance-sensitive and are using large tables, multiple joins would be better than this subquery approach.
The simplified version answering your question's requirements:
select af.AvailableFieldID
from AvailableFields af -- all available fields
left join (select distinct f.AvailableFieldID
from Config c
join Fields f
on c.ConfigID = f.ConfigID
where c.UserID = #UserID) AS UserHas -- the fields the user has
on af.AvailableFieldID = UserHas.AvailableFieldID
where UserHas.AvailableFieldID is null -- a field match for the user isn't there
This will also return AvailableFieldID that are not in a Config.
The version you probably want b/c it can be multi-users:
select u.UserID, af.AvailableFieldID
from Users u -- all users
cross join AvailableFields af -- all fields
left join (select distinct f.AvailableFieldID, c.UserID
from Config c
join Fields f
on c.ConfigID = f.ConfigID) AS UserHas -- the fields each user has
on u.UserID = UserHas.UserID
and af.AvailableFieldID = UserHas.AvailableFieldID
where UserHas.AvailableFieldID is null -- a field match for the user isn't there
and (#UserID is null or u.UserID = #UserID) -- option to limit it to one user

SQL Query With Join for 2 Tables

I'm unable to form a query with the following tables, which will find out all the Notes from Note table, which is created by any user, who belongs to the logged in user's same company.
Note:
note_id (int),
note_text (varchar),
created_by (int)
User:
user_id (int),
company_id (int)
Logged in user's user id is passed as parameter to the query.
I want to pick up notes from the table Notes where created_by in (user_id of all users whose company_id = company_id of LOGGED_IN_USER)
Please help me to formulate out the query. Looks pretty straight forward, but just can't reach to it's end.
I'm not sure if LOGGED_IN_USER is a table or another object, but if it is a table with the columns you referenced, a join like this would work.
select note_text
from Note n
JOIN User u ON u.user_id = n.created_by
JOIN LOGGED_IN_USER lin ON lin.user_id = u.user_id
and lin.company_id = u.company_id
u might need a Foreign Key for user_id to Notes. and use INNER JOIN
Thanks Vinnie and all for your responses. I finally succeeded to figure out the query. LOGGED_IN_USER_ID is just a numeric parameter which should be passed to the query.
select n.* from Note n where
n.created_by in (
select u1.user_id from User u1 inner join User u2
on u1.company_id=u2.company_id and u2.user_id = :LOGGED_IN_USER_ID*
)
Thanks again.
If i am not misunderstood your question,Try this way
SELECT note_text
FROM Note n
INNER JOIN User u ON u.user_id = n.created_by
WHERE n.created_by= (select u.user_id from User where company_id=LOGGED_IN_USER LIMIT 1 )