Where clause in sql query remove also null values - sql

I have these tables:
'Users'
id email name last_access
1 luca#gmail.com Luca Pluto 2012-10-05 17:21:22.0
2 pippo#gmail.com Irene Pippo 2012-10-05 17:22:25.0
'Nets_permissions'
user_id network_id perm
1 1234 3
1 1235 1
2 1235 3
I've written this query:
SELECT u.id, u.name, n.perm
FROM users as u LEFT OUTER JOIN nets_permissions as n
ON u.id = n.user_id
WHERE n.network_id=1234 AND n.perm <> 3
because I want users that already have a permission for network_id (1234) , but also users that don't have a permission for the network_id. In other words I would have this result query:
2 null null
because the user Luca Pluto with id=1, for the net 1234, have perm=3 so I want left out. Instead, the user Irene Pippo with id=2 doesn't have any permission on the 1234 net. So it's row must have net_id and perm set to null.
My query result is empty. I don't know why. Without the clause n.perm <> 3 seems to work well, but after also the null value are left out, not only the rws with perm=3.
I've also tried in this way:
SELECT u.id, u.name, n.perm FROM users as u LEFT OUTER JOIN
(select * from nets_permissions WHERE network_id=1234) as n on u.id = n.user_id
WHERE n.perm <> 3
but it doesn't work. without the WHERE clause all works. After no. The result query is empty.
How I can resolve this problem? I need that the perm column is a value or null, I can't remove this column.

The right solution is:
SELECT u.id, u.name, n.perm FROM users as u LEFT OUTER JOIN
(select * from nets_permissions WHERE network_id=1234) as n on u.id = n.user_id
WHERE (n.perm <> 3 or n.perm is NULL)
Here Working with NULL Values there is a expanation of the treatment of NULL values in MySQL
Thank you all for your help!

Many SQL dialect use a special trinary logic with NULL the third possible value additional to true and false.
Anything compared to NULL results to NULL which in turn is handled as false.
So x = null will result in false for all x, just as x != null
If you want to include NULL values in the result you have to add special handling for that (Oracle syntax):
SELECT u.id, u.name, n.perm
FROM users as u LEFT OUTER JOIN nets_permissions as n
ON u.id = n.user_id
WHERE n.network_id=1234
AND (n.perm <> 3 or n.perm is not null)

SELECT u.id, u.name, n.perm
FROM
users as u
LEFT OUTER JOIN
nets_permissions as n ON u.id = n.user_id
WHERE
n.network_id = 1234 and n.perm <> 3
or
n.network_id <> 1234
or
n.network_id is null

I like users that user the "JOIN" syntax. It has additional benefit, aside from making the code easier to read, that people don't realize.
SELECT u.id, u.name, n.perm
FROM users as u LEFT OUTER JOIN nets_permissions as n
ON u.id = n.user_id
AND n.network_id=1234
WHERE COALESCE(n.perm,-1) <> 3

Related

Database join where

Database
Users
id
lastname
firstname
1
Sardor
Sattarov
2
Nurmuhammad
To’xtayev
3
Jasur
Sattarov
Group_items
id
student_id
group_id
1
2
55
2
1
55
3
2
11
Return
example 1
condition
users.id == group_items.student_id do not publish a table that satisfies this desire group_items.id == 55
id
lastname
firstname
3
Jasur
Sattarov
example 2
condition
users.id == group_items.student_id do not publish a table that satisfies this desire group_items.id == 11
id
lastname
firstname
1
Sardor
Sattarov
3
Jasur
Sattarov
Looks like you want OR instead of AND.
SELECT
*
FROM
users u
LEFT JOIN group_items gi ON u.id = gi.student_id
WHERE
gi.student_id IS NULL
OR gi.group_id <> 5
Studends without a group plus studends in all groups but 5.
Please try this,
Example 1:
SELECT
U.ID,U.LASTNAME,U.FIRSTNAME
FROM
USERS U
LEFT JOIN
GROUP_ITEMS G
ON U.ID=G.STUDENT_ID
WHERE G.GROUP_ID <>55
Example 2:
SELECT
U.ID,U.LASTNAME,U.FIRSTNAME
FROM
USERS U
LEFT JOIN
GROUP_ITEMS G
ON U.ID=G.STUDENT_ID
WHERE G.GROUP_ID <>11
You can use join statements in SQL
For Example
for return 1:
SELECT * FROM users u left join group_items gi on gi.student_id = u.id
this query will return all students with their group_id
for filter by group you can use where statement.
SELECT * FROM users u left join group_items gi on gi.student_id = u.id where gi.group_id<>11

select a column from another table mulipletimes problem

User
USER_ID USERNAME
1 -
2 Chris
3 Dave
4 Vlad
Issue
Creator RESOLVER VERIFIER
2 3 4
2 3 1
3 1 1
expected output:
Creator RESOLVER VERIFIER
Chris Dave Vlad
Chris Dave -
Dave - -
current code I have:
SELECT creatorid.username, resolverid.username, verifierid.username
FROM issue
JOIN user creatorid ON issue.creator = creatorid.user_id
JOIN user resolverid ON issue.resolver = resolverid.user_id
JOIN user verifierid ON issue.verifier = verifierid.user_id
do i have to join the table 3 times to get the corresponding username of the user_id in issue table or is there is a simpler way of doing this? Asking as this is a simplified version of the tables, the User and Issue table contains a lot of other columns. Thanks
Because of the join, you will see each issue three times which is not what you want. You could use three scalar subqueries to get around that:
select i.id,
(select username from users u1 where u1.user_id = i.creator) as creator,
(select username from users u2 where u2.user_id = i.resolver) as resolver,
(select username from users u3 where u3.user_id = i.verifier) as verifier
from issue i;
This isn't going to be fast though.
Another option is to aggregate all user_id / username pairs into a JSON object, then use that in a sub-query:
select i.id, -- other columns from the issue table
u.names ->> i.creator::text as creator,
u.names ->> i.resolver::text as resolver,
u.names ->> i.verifier::text as verifier
from issue i
join lateral (
select jsonb_object_agg(user_id, username) as names
from users u
where u.user_id in (i.creator, i.resolver, i.verifier)
) u on true;
The traditional way to do this is:
select i.*, uc.username, ur.username, uv.username
from issue i left join
users uc
on uc.user_id = i.creator left join
users ur
on ur.user_id = i.resolver left join
users uv
on uv.user_id = i.verifier;

SQL JOIN Returning no values

I am working with 3 tables with the following Names and columns:
*Table 1*
**Users**
UserID UserName UserTypeNumber
1 John 1N
2 Mary 1N
3 Doe 1N
4 Sullivan 2N
5 Sally 1N
**Key = UserID**
*Table 2*
**MobileUsers**
Userid MobileAccess
1 Yes
2 Yes
3 Yes
4 Yes
5 No
**Key = UserID**
*Table 3*
**PanCards**
UserID CARD_NUMBER
3 2222
4 3333
5 1111
Key = UserID
Explanation:
Every user is available in both Users and MobileUsers table
However, not all users are present in PanCards table. This is
because only users that have been assigned a Card appears in the
PanCards table. In this case Doe with UserID=3 and Sullivan with UserID=4 have a card, hence they appear in PanCards table
Problem:
What I want to achieve is to filter out the users from
MobileUsers table that have MobileAccess equivalent to Yes and thier UserTypeNumber equivalent to 1N in the Users table but are not present in the PanCards table.
What I have so far is the below SQL Query:
SELECT MobileUsers.Userid, MobileUsers.MobileAccess
FROM MobileUsers
INNER JOIN Users
ON MobileUsers.Userid = Users.UserID
INNER JOIN PanCards
ON Users.UserID = PanCards.UserID
WHERE MobileUsers.MobileAccess = 'Yes'
AND
Users.UserTypeID = '1N'
AND
MobileUsers.Userid NOT IN
(SELECT PanCards.UserID FROM PanCards)
Result is an Empty table
Userid MobileAccess
However what i want is to have the below result returned:
Userid MobileAccess
1 Yes
2 Yes
How do i fix this and get the correct results please ?
If you want to use JOIN, then use a LEFT JOIN for PanCards and check for no matches:
SELECT mu.*
FROM MobileUsers mu JOIN
Users u
ON mu.Userid = u.UserID LEFT JOIN
PanCards pc
ON pc.UserID = mu.UserID
WHERE mu.MobileAccess = 'Yes' AND
u.UserTypeID = '1N' AND
pc.UserID IS NULL;
I think your query would work without the join to PanCards.
WITH NotPan -- First get users that are not in the PanCards table
AS
(
select * from Users as u
where u.userid not in (select userid from PanCards)
)
-- Easy from here
select * from NotPan as n
inner join mobileUsers m on m.userid = n.userid
inner join Users as u on n.userid = u.userid
WHERE m.MobileAccess = 'Yes' and u.UserTypeNumber = '1N'

Query that joins two table where match exists and removes result if ID exists in another table

This query gets the the ID, First Name, Date of Birth by joining two tables together where a mutual match exists
Example of mutual match:
Amy likes Mary
Mary likes Amy
SELECT u.ID, u.firstname, u.dob, i.[Image]
FROM [dbo].[User] AS u
INNER JOIN [dbo].[Images] AS i ON u.ID = i.Id
WHERE u.ID IN (
SELECT userB FROM [dbo].[LikesRefined]
WHERE userA = #ID OR userB = #ID
UNION
SELECT userB FROM [dbo].[LikesRefined]
WHERE userA = #ID OR userB = #ID
);
I want to filter this result by using except clause on another table but I keep getting this error
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
except
(select paidA
from [dbo].[Matches]
WHERE paidA = #ID
AND (userA = #ID or userB = #ID))
end
I'm still confused, but I think this may do the trick:
SELECT u.ID ,
u.firstname ,
u.dob ,
i.[Image]
FROM [dbo].[User] AS u
INNER JOIN [dbo].[Images] AS i ON u.ID = i.Id
INNER JOIN dbo.[LikesRefined] lr ON (u.ID = lr.userA OR u.ID = lr.userB)
LEFT OUTER JOIN dbo.Matches m ON u.ID = m.paidA
AND ( m.userA = u.ID OR m.userb = u.ID )
WHERE (lr.userA = #ID OR lr.userB = #ID)
AND m.paidA IS NULL
We get rid of the union operator and just check for the ID in either userA or userB in the LikeRefined table. Then we left join to dbo.Matches and just look for records where there is no match.
When using union operator all select statements must have the same number of columns

Why is Count(*) returning unexpected number?

This is my query:
Select COUNT(*)
From
Users u
Inner Join
UsersLoginHistory uh On u.UserID = uh.UserID
Where
1 = 1
And
u.AccountID = 37
Group By u.UserID
What I'd like to be able to get is Count(*) should be returning a number after grouping on u.UserId. But it returns the Count(*) before the group by is made.
So I can rewrite the above query as:
Select COUNT(*)
From (
Select u.Username
From
Users u
Inner Join
UsersLoginHistory uh On u.UserID = uh.UserID
Where
1 = 1
And
u.AccountID = 37
Group By u.UserID
) v
But I need to find out why is the Count(*) returning records before a group by is made and how can I fix the 1st query itself.
EDIT: Sample Records
Users table
UserId Username
102 tom.kaufmann
UserLoginHistory table
UsersLoginHistoryID UserID LoginDateTime LogoutDateTime IPAddress
1 102 2012-09-28 01:16:00 NULL 115.118.71.248
2 102 2012-09-28 01:29:00 2012-09-28 01:29:00 127.0.0.1
3 102 2012-09-28 01:32:00 2012-09-28 01:32:00 127.0.0.1
4 102 2012-09-28 01:41:00 NULL 115.118.71.248
5 102 2012-09-28 01:43:00 2012-09-28 07:04:00 115.118.71.248
and so on..
Haven't writted every single record in this DB.
Based on your second query which you say returns the desired results (and assuming UserID is the PK of Users) I presume this is what you need
SELECT Count(UserID)
FROM Users u
WHERE u.AccountID = 37
AND EXISTS (SELECT *
FROM UsersLoginHistory uh
WHERE u.UserID = uh.UserID)
This will be more efficient than expanding out all the joined rows then collapsing them again with Group By u.UserID and counting the number of rows that result.
Change the first line to:
Select COUNT(*), u.UserID
This should provide you a list of UserIds and the count of entries in the UsersLoginHistory table.
SELECT u.UserId
, COUNT(uh.*)
FROM Users u
INNER JOIN UsersLoginHistory uh ON u.UserID = uh.UserID
WHERE u.AccountID = 37
GROUP BY u.UserID
But I need to find out why is the Count(*) returning records before a group by is made and how can I fix the 1st query itself
It is counting the number of lines for each UserID (number of logins), which is exactly how group by is supposed to work.
COUNT is an aggregate function and this is how it's supposed to work. You get count per grouping.
In your first query you are querying the number of userloginhistory per user. In your second query you are querying number of users with login history.
http://msdn.microsoft.com/en-us/library/ms173454.aspx