MySql Join a View Table as a Boolean - sql

I have a users table, and a view table which lists some user ids... They look something like this:
Users:
User_ID | Name | Age | ...
555 John Doe 35
556 Jane Doe 24
557 John Smith 18
View_Table
User_ID
555
557
Now, when I do run a query to retrieve a user:
SELECT User_ID,Name,Age FROM Users WHERE User_ID = 555
SELECT User_ID,Name,Age FROM Users WHERE User_ID = 556
I also would like to select a boolean, stating whether or not the user I'm retrieving is present in the View_Table.
Result:
User_ID Name Age In_View
555 John Doe 35 1
556 Jane Doe 24 0
Any help would be greatly appreciated. Efficiency is a huge plus. Thanks!!

SELECT Users.User_ID,Name,Age, View_Table.User_ID IS NOT NULL AS In_View
FROM Users
LEFT JOIN View_table USING (User_ID)
WHERE User_ID = 555

SELECT
User_ID, Name, Age,
CASE WHEN v.UserID is not null THEN 1 ELSE 0 END AS In_View
FROM Users u
LEFT JOIN View_Table v on u.User_ID = v.UserID
WHERE UserID ...;

I would do a LEFT JOIN. So long as you have key/index for User_ID, it should be very efficient.
SELECT User_ID,Name,Age, IF(View_Table.User_ID, 1, 0) AS In_View
FROM Users LEFT JOIN View_Table USING(User_ID)
WHERE User_ID = 555

I know this is an "Old" question but just happened upon this and none of these answers seemed to be that good. So I thought I would throw in my 2 cents
SELECT
u.User_ID,
u.Name,
u.Age,
COALESCE((SELECT 1 FROM View_Table AS v WHERE v.User_ID = u.User_ID ), 0) AS In_View
FROM
Users AS u
WHERE
u.User_ID = 555
Simply select 1 with a correlated query ( or null ) then to get the 0 we can use the handy function COALESCE which returns the first non-null value left to right.

Related

SQL Server | Select all specific duplicate in columns

My problem right now is that I need to make an statement where select all rows that are duplicates with specific needs.
For example I got table 1 (users):
Users:
----------------------------------------------
ID name lastname birth file number
1 Max Lix 2015-02-01 D43-892
2 Chris Maura 2010-12-25 E33-722
4 Lena Paul 2005-05-11 S85-458
5 Max Lix 2019-02-01 D23-992
6 Lena Paul 2005-05-11 S84-488
7 Lena Paul 2005-05-11 S75-258
----------------------------------------------
Address(u_ID = ID of Users table):
----------------------------------------------
ID u_ID Street number zip
1 1 Heystr. 12 4556
2 2 Nostr. 2 8978
3 4 Yesstr. 8a 2545
I need to get all rows where the name, lastname and birth does match with other rows and also get the address for that person.
The result should look like this:
Result:
----------------------------------------------
name lastname birth filenumber address
Max Lix 2015-02-01 D43-892 Heystr. 12 4556
Max Lix 2019-02-01 D23-992 Heystr. 12 4556
Lena Paul 2005-05-11 S85-458 Yesstr. 8a 2545
Lena Paul 2005-05-11 S84-488 Yesstr. 8a 2545
Lena Paul 2005-05-11 S75-258 Yesstr. 8a 2545
The first idea that I had was to use GROUP BY and HAVING but that does only return one row but I need every single duplicate matching the name, lastname and birth.
Use this:
select u.name, u.lastname, u.birth, u.filenumber, concat(a.street, ' ', a.number, ' ', a.zip) address
from users u
left join address a
on a.u_id = u.id
where
exists (
select 1 from users
where users.name = u.name and user.lastname = u.lastname and user.birth = u.birth and users.id <> u.id
)
With the condition:
users.name = u.name and user.lastname = u.lastname and user.birth = u.birth and users.id <> u.id
you can find the dupilcates.
Use inner join instead of left join if you want the duplicates only once.
SELECT name, lastname, birth, filenumber, concat(street,' ' , number, ' ', zip) as address
FROM Users A, Adress
WHERE u_id = a.id
AND (SELECT COUNT(1)
FROM Users B
WHERE A.name = B.name
AND A.lastname = B.lastname) > 1
with duplicate as ( -- this CTE makes a list of duplicated user_IDs
Select u.id
from users
group by name, lastname, birth
having count(*) >= 2
)
Select concat(street,' ' , number, ' ', zip) as address,
name, lastname, birth, filenumber
from duplicates d -- gather the data
join addresses on d.id=uid
join users on u.id=d.uid
will return you a report of all the people having an homonym with same birthday
Please try below,
select U.name,U.lastname,U.birth,U.filenumber,concat(street,' ',number,' ',zip) as address
from Users U join Address A on
U.ID=A.u_Id
group by name,lastname,birth
having count(*)>1

How to find distinct users in multiple tables

I have a table called users that holds users ids, as well as a few tables like cloud_storage_a, cloud_storage_b and cloud_storage_c. If a user exists in cloud_storage_a, that means they are a connected to cloud storage a. A user can exist in many cloud storages too. Here's an example:
users table:
user_id | address | name
-------------------------------
123 | 23 Oak Ave | Melissa
333 | 18 Robson Rd | Steve
421 | 95 Ottawa St | Helen
555 | 12 Highland | Amit
192 | 39 Anchor Rd | Oliver
cloud_storage_a:
user_id
-------
421
333
cloud_storage_b:
user_id
-------
555
cloud_storage_c:
user_id
-------
192
555
Etc.
I want to create a query that grabs all users connected on any cloud storage. So for this example, users 421, 333, 555, 192 should be returned. I'm guessing this is some sort of join but I'm not sure which one.
You are close. Instead of a JOIN that merges tables next to each other based on a key, you want to use a UNION which stacks recordsets/tables on top of eachother.
SELECT user_id FROM cloud_storage_a
UNION
SELECT user_id FROM cloud_storage_b
UNION
SELECT user_id FROM cloud_storage_c
Using keyword UNION here will give you distinct user_id's across all three tables. If you switched that to UNION ALL you would no longer get Distinct, which has it's advantages in other situations (not here, obviously).
Edited to add:
If you wanted to bring in user address you could use this thing as a subquery and join into your user table:
SELECT
subunion.user_id
user.address
FROM
user
INNER JOIN
(
SELECT user_id FROM cloud_storage_a
UNION
SELECT user_id FROM cloud_storage_b
UNION
SELECT user_id FROM cloud_storage_c
) subunion ON
user.user_id = subunion.user_id
That union will need to grow as you add more cloud_storage_N tables. All in all, it's not a great database design. You would be much better off creating a single cloud_storage table and having a field that delineates which one it is a, b, c, ... ,N
Then your UNION query would just be SELECT DISTINCT user_id FROM cloud_storage; and you would never need to edit it again.
You need to join unknown(?) number of tables cloud_storage_X this way.
You'd better change your schema to the following:
storage:
user_id cloud
------- -----
421 a
333 a
555 b
192 c
555 c
Then the query is as simple as this:
select distinct user_id
from storage;
select u.* from users u,
cloud_storage_a csa,
cloud_storage_b csb,
cloud_storage_c csc
where u.user_id = csa.user_id or u.user_id = csb.user_id or u.user_id = csc.user_id
You should simplify your schema to handle this type of queries.
To get columns from your users table for all (distinct) qualifying users:
SELECT * -- or whatever you need
FROM users u
WHERE EXISTS (SELECT 1 FROM cloud_storage_a WHERE user_id = u.user_id) OR
EXISTS (SELECT 1 FROM cloud_storage_b WHERE user_id = u.user_id) OR
EXISTS (SELECT 1 FROM cloud_storage_c WHERE user_id = u.user_id);
To just get all user_id and nothing else, #JNevill's UNION query looks good. You could join the result of this to users to the same effect:
SELECT u.* -- or whatever you need
FROM users u
JOIN (
SELECT user_id FROM cloud_storage_a
UNION
SELECT user_id FROM cloud_storage_b
UNION
SELECT user_id FROM cloud_storage_c
) c USING user_id);
But that's probably slower.

Pulling Datetime when using COUNT(UserID)

I have the tables Users
UserID FirstName LastName Email
------ --------- -------- -----
1 Fred Smith fs#abc.com
2 Bob Hill bh#abc.com
3 Jane Doe jd#abc.com
and LoginSession
LoginSessionID UserID StartDate
-------------- ------ ---------
1 1 2014-11-23 08:37:14.836
2 1 2014-11-25 11:13:53.225
3 2 2014-12-01 03:15:33.846
4 1 2014-12-01 17:34:19.036
5 3 2014-12-05 12:55:01.998
6 1 2014-12-14 17:20:14.636
7 3 2014-12-15 10:02:17.376
What I am trying to do is find the users who have logged on only once and find out when that was.
I have managed to find the users who have logged on only once by using
SELECT
U.FirstName, U.LastName, COUNT(L.UserID) AS Visits
FROM
LoginSession L
JOIN
Users U ON U.UserID = L.UserID
GROUP BY
U.FirstName, U.LastName
HAVING
COUNT(L.UserID) = 1
But I also want to pull through the L.StartDate of those users. If I add it to the select query I get an error because it's not contained in an aggregate function or GROUP BY clause. If I add it the the GROUP BY line (to avoid that error) I get each and every login handily marked as 1 visit!
I also tried using a subquery but I got an error because it returned more than one result.
I really am totally stumped!
You can do this with aggregation:
select UserId, min(StartDate) as StartDate
from LoginSession ls
group by UserId
having count(*) = 1;
The min() returns the value you want, because there is only one row that matches. You can use an addition join to get additional information about the users.
select u.*, lsu.StartDate
from Users u join
(select UserId, min(StartDate) as StartDate
from LoginSession ls
group by UserId
having count(*) = 1
) lsu
on lsu.UserId = u.UserId;
You can use windowed version of COUNT:
SELECT FirstName, LastName, StartDate
FROM (
SELECT U.FirstName, U.LastName, L.StartDate,
COUNT(*) OVER (PARTITION BY U.UserID) AS cnt
FROM LoginSession L
JOIN Users U ON U.UserID = L.UserID ) AS t
WHERE t.cnt = 1
COUNT with OVER clause will return the number of records per U.UserID. Using an outer query you can fetch exactly these records.
Demo here

how to display a row that is null instead of 0

I am getting a correct result, but now instead of showing me result that is 0 I want them to show me null result . How could I get results null instead of 0 ?
SELECT w.FIRST_NAME,w.LAST_NAME,COUNT(s.SECTION_ID) AS COUNTED_SECTIONS
FROM INSTRUCTOR w LEFT OUTER JOIN SECTION s
ON w.INSTRUCTOR_ID = s.INSTRUCTOR_ID
GROUP BY w.FIRST_NAME,w.LAST_NAME
ORDER BY w.LAST_NAME;
currently showing
FIRST_NAME LAST_NAME COUNTED_SECTIONS
------------------------- ------------------------- ----------------
Rick Chow 0
Marilyn Frantzen 10
Fernand Hanks 9
Charles Lowry 0
etc
but I want
FIRST_NAME LAST_NAME COUNTED_SECTIONS
------------------------- ------------------------- ----------------
Rick Chow
Marilyn Frantzen 10
Fernand Hanks 9
Charles Lowry
etc
I've tried it with NVL and it doesn't work
NVL(COUNT(s.SECTION_ID),NULL) AS COUNTED_SECTIONS
I think NULLIF() is available in oracle:
SELECT w.FIRST_NAME,w.LAST_NAME,NULLIF(COUNT(s.SECTION_ID),0) AS COUNTED_SECTIONS
FROM INSTRUCTOR w LEFT OUTER JOIN SECTION s
ON w.INSTRUCTOR_ID = s.INSTRUCTOR_ID
GROUP BY w.FIRST_NAME,w.LAST_NAME
ORDER BY w.LAST_NAME;
Try nullif:
SELECT w.FIRST_NAME,w.LAST_NAME, NULLIF(COUNT(s.SECTION_ID), 0) AS COUNTED_SECTIONS
FROM INSTRUCTOR w LEFT OUTER JOIN SECTION s
ON w.INSTRUCTOR_ID = s.INSTRUCTOR_ID
GROUP BY w.FIRST_NAME,w.LAST_NAME
ORDER BY w.LAST_NAME;
You can use DECODE in order to decide what you want to display
DECODE(COUNT(s.SECTION_ID),0, NULL, COUNT(s.SECTION_ID)) AS COUNTED_SECTIONS

Exclude rows with a column containing a value if multiple rows exist for

Table has
User Value
john 284
john 200
john 5
sally 245
sally 180
sally 10
bill 90
bill 1000
bill 284
greg 10
greg 90
greg 2000
If User has a value of 284 for example, then I want the result set not to include him
I am not sure how to check all rows of User to see if there is the 284 value and then not show that user in the resultset if it is there. The resultset should be distinct.
The end resultset should be
User
greg
sally
Use not exists:
select distinct
user
from
users u
where
not exists (
select
1
from
users u2
where
u2.user = u.user
and u2.value = 284
)
What this does is it grabs all the users from the users table where they don't have a row with the value 284 in the users table. You can also do exists as a converse (finding only users with a 284 value).
Additionally, use a distinct on the select to limit the users returned to their unique values.
Select distinct User from table
where User not in ( Select User from table
where value =284)
Another option is a self-join:
SELECT DISTINCT u1.[User]
FROM users u1
LEFT OUTER JOIN users u2 ON u2.[User] = u1.[User] AND u2.Value = 284
WHERE u2.[User] IS NULL
You can use group by user and also count how many users with value != 284
Here is SQL
Select `User`
,count(*)- SUM(CASE WHEN `Value` != 284 THEN 1 ELSE 0 END) 284Val
from table
group by `User`
having 284Val = 0;