SQL Query to get mapping of all users to their logins - sql

What's a query that I can use to get a list of all logins associated with each user in SQL Azure?
So far I've found the following two queries to get all users and all logins, but I haven't found any way to see which user goes with which login:
SELECT * from sys.sql_logins -- get all logins
SELECT * from sys.sysusers -- get all users
In case you find it helpful, here's the documentation for the structures of those the tables:
sys.sql_logins:
https://msdn.microsoft.com/en-us/library/ms174355.aspx?f=255&MSPPError=-2147217396
Column names: name, principal_id, sid, type, type_desc, is_disabled, create_date, modify_date, default_database_name, default_language_name, credential_id, is_policy_checked, is_expiration_checked, password_hash
sys.sysusers: https://msdn.microsoft.com/en-us/library/ms179871.aspx
Column names: uid, status, name, sid, roles, createdate, updatedate, altuid, password, gid, environ, hasdbaccess, islogin, isntname, isntgroup, isntuser, issqluser, isaliased, issqlrole, isapprole

It's hard to tell you your correct answer b/c we don't know the structure of your tables. If you share that we can help more. But below should get you to where you need to go.
They way to do it is by a MySQL JOIN. In this case you should use a INNER or OUTER JOIN depending on how your database is structured.
If you have 2 tables that are structured below you can do an FULL OUTER JOIN
[sys.sql_logins]
| sid| userID | name |
| 1 | 1 | ssmith |
| 2 | 2 | bbob |
[sys.sysusers]
| sid| name |
| 1 | Sam Smith |
| 2 | Billy Bob |
You can use the following query to do it
SELECT A.name as userName, B.name as login
FROM sys.sysusers A
FULL OUTER JOIN sys.sql_logins B
ON A.sid = B.sid
This will result in :
| userName | logins |
| Same Smith | ssmith |
| Billy Bob | bbob |
Here is a link to more types of MySQL Joins
https://www.sitepoint.com/understanding-sql-joins-mysql-database/
http://dev.mysql.com/doc/refman/5.7/en/join.html
http://www.w3schools.com/sql/sql_join.asp

I think you can join on the sid, try this (but maybe just select whatever columns you want):
select l.*, u.*
from sys.sql_logins l
join sys.sysusers u on l.sid = u.sid

Related

SQL Query to show results that don't have a relation to variable

For an assignment I have which includes a delete and add friend system (like Facebook), I've made a query that works by using two SQL tables, one which includes a friend_id, name and other information, and another which holds two friend_id columns, that show the relationship with the users and if they're friends.
User Table (friends)
| friend_id | profile_name |
|:---------- |:------------:|
| 1 | John |
| 2 | Peter |
| 3 | Alex |
| 4 | Nick |
---------------------------
Friendship Table (myfriends)
| friend_id1 | friend_id2 |
|:---------- |:----------:|
| 1 | 3 |
| 2 | 4 |
| 3 | 1 |
| 4 | 2 |
-------------------------
I am wanting to get a query which selects people that don't have a connection with a result (I want to show anyone who doesn't have a connection to friend_id '1', so only want to show users 2 and 4), and then display their name.
I have a query that selects the ones which have the relation which is:
SELECT friends.profile_name,friends.friend_id FROM `myfriends` JOIN `friends` ON friends.friend_id = myfriends.friend_id2 WHERE `friend_id1` = 1;
The query bellow shows all results from the table, and even using '!=', it doesn't select those who don't have a relation to friend_id '1'
SELECT friends.profile_name,friends.friend_id FROM `myfriends` JOIN `friends` ON friends.friend_id = myfriends.friend_id2 WHERE `friend_id1` != 1;
How can I fix this query so it shows all results but those connected to ‘friend_id1’ = 1
with connected as (SELECT friend_id,
myfriends.friend_id2 friend
FROM myfriends
JOIN friends
ON friends.friend_id = myfriends.friend_id1
WHERE friend_id1 = 1)
select *
from friends
where friend_id not in (select distinct friend from connected union all select distinct friend_id from connected)
you cannot change the where clause as it specifies which user you want to focus on.
So first get the users that are connected (in the first cte), and then select all users except those found in the first result of the connected users.
By the way, your example is misleading as it can be solved with a bug by doing something simple in the join.
edit
while it wasn't clease which version you were using, (I thought with clause is available in the newer mysql versions) I created another solution that is working on mysql 5.6 and should work for you as well:
select f.*
from friends f
left join (
SELECT friend_id, myfriends.friend_id2 friend
FROM myfriends
JOIN friends
ON friends.friend_id = myfriends.friend_id1
WHERE 1 in (friend_id,friend_id2)) f1
on f1.friend = f.friend_id
where f1.friend is null
it has a nicer implementation in one part (1 in one of 2 columns), and uses a left join that takes the nulls from the right table.

Redshift join each values in an array

I have a table like below (its actually the pg_group table)
group_id | group_name | userid
_____________________________________
101 | gr1 | {100,101}
102 | gr2 | {100,110,120}
I have another table where I can see the name of the user id.
userid | username
______________________
100 | user1
101 | user2
110 | user3
120 | user4
I want to join these 2 tables and generate the output like this.
group_id | group_name | username
_____________________________________
101 | gr1 | user1,user2
102 | gr2 | user1,user3,user4
I tried listagg and etc, but it didn't work as expected.
Update:
I tried this one, but list agg seems not working.
SELECT I.group_name, listagg(J.username,',')
FROM pg_group I
LEFT JOIN pg_user J
ON J.userid = ANY(I.userid)
GROUP BY I.group_name
ERROR: One or more of the used functions must be applied on at least one user created tables. Examples of user table only functions are LISTAGG, MEDIAN, PERCENTILE_CONT, etc;
Here first I have converted arrays of user_ID INTO ROWS WITH UNNEST THEN COLLECTED username against those user_id and at last with string_agg() function again those usernames have been grouped into a comma separated column.
select group_id,group_name,string_agg(username,',')usrname from
(select group_id,group_name,unnest(userid::text[])user_id from pg_group )pg
inner join pg_user u
on pg.user_id::int = u.userid
group by group_id,group_name
From googling so far I have understood that you cannot use listagg() if there is no user defined table is involved. I have found a way around. But I cannot check it since I don't have Redshift platform. Please check it out:
select group_name,listagg(username, ', ') within group (order by column_name)
from
(
SELECT I.group_name,J.username
FROM pg_group I
LEFT JOIN pg_user J
ON J.userid = ANY(I.userid)
left join (select top 1 1 from my_schema.my_table)
on 1=1
)
Instead of my_schema.my_table Please use any of your user defined table

Rows which do not exist in a table

I have a lists of names John, Rupert, Cassandra, Amy, and I want to get names which are not exists in table: Cassandra, Amy
How should I write such query?
My table:
+----+--------+-----------+------+
| id | name | address | tele |
+----+--------+-----------+------+
| 1 | Rupert | Somewhere | 022 |
| 2 | John | Doe | 029 |
| 3 | Donald | Armstrong | 021 |
| 4 | Bob | Gates | 022 |
+----+--------+-----------+------+
Think in sets. You add names to a the result set with UNION ALL, you remove names from the result set with EXCEPT.
select 'John'
union all
select 'Rupert'
union all
select 'Cassandra'
union all
select 'Amy'
except
select name from mytable;
Build up a list of your names to check and do a left join to the users table:
with to_check (name) as (
values
('John'), ('Rupert'), ('Cassandra'), ('Amy')
)
select tc.name as missing_name
from to_check tc
left join the_table tt on tt.name = tc.name
where tt.name is null;
SQLFiddle example: http://sqlfiddle.com/#!15/5c4f5/1
Hope your list is in form of table lets its be table b and your original table as a
now SQL query goes like it
Select name from a where name not in (select name from b);
Think this will give you solution as per my understanding. Also if further details are required please comment.
Also its more important to search for an answer as it look like its a question from a book/Class. Please try out to find solution could have got much more information like link below
How to write "not in ()" sql query using join

A double outer join

I have a table People, a table Permission and a table Action. Permission is there to provide a many-to-many relationship between People and Action.
My goal is simple : I want to look for one person in People, I want to see the permission listed in Permission, AND every action available, wether the person has the permission or not.
Note that a member of People is not necessary represented in Permission. So, "John" is only allowed to do something if he's got the permission written in the database.
Ideally, the result would look something like :
+-------------------------------------------+
+ People.name | Action.name |Allowed |
+-------------------------------------------+
| John Doe | Launching missiles | N |
| John Doe | Deleting code | Y |
+-------------------------------------------+
Before I get to there, I'm simply tring to build a simple query with every data.
Getting the list of permission of someone, even if he is not present in the permission table is easy :
SELECT * FROM people pp LEFT OUTER JOIN permission pr ON pp.id = pr.people_id
WHERE pp.name = 'John';
Getting the list of permission and actions is easy :
SELECT * FROM permission pr LEFT OUTER JOIN action a ON pr.action_id = a.id
However, I can't seem to perform a double outer join that would get me everything I want :
SELECT * FROM people pp LEFT OUTER JOIN permission pr ON pp.id = pr.permission_id
LEFT OUTER JOIN people WHERE pp.name = 'John'
Shows John, the fact that he's got no permission... but no actions whatsoever.
In other words, results look something like :
+-----------------------------------------+
+ Name | People_id | Action_id |Action |
+-----------------------------------------+
| John | | | |
+-----------------------------------------+
When I wanted :
+-----------------------------------------------------------+
+ Name | People_id | Action_id |Action |
+-----------------------------------------------------------+
| John | | | Launching missiles |
| John | | | Deleting codes |
| John | | | (every other actions) |
+-----------------------------------------------------------+
So, is what I want possible ? If so, how can I achieve it ? (I'm using PostgreSQL).
edit: Here is a sqlfiddle : http://sqlfiddle.com/#!2/6d502
SELECT pp.name, pr.id_people, pr.id_action, a.name as action_name
FROM people pp
CROSS JOIN action a
LEFT JOIN permission pr
ON pr.id_people = pp.id
AND pr.id_action = a.id
SQLFiddle: http://sqlfiddle.com/#!15/5a7b1/4
To filter by person name add to query:
WHERE pp.name = 'John'
This should work.
SELECT
P.name as "people.name",
IFNULL(pm.id_people,''),
IFNULL(pm.id_action,''),
A.name as "action.name"
FROM Action A
CROSS JOIN People P
LEFT JOIN permission pm
ON pm.id_action = a.id
AND pm.id_people = p.id
WHERE p.name = 'John'

One table, need multiple values from different rows/tuples

I have tables like:
'profile_values'
userID | fid | value
-------+---------+-------
1 | 3 | joe#gmail.com
1 | 45 | 203-234-2345
3 | 3 | jane#gmail.com
1 | 45 | 123-456-7890
And:
'users'
userID | name
-------+-------
1 | joe
2 | jane
3 | jake
I want to join them and have one row with two of the values like:
'profile_values'
userID | name | email | phone
-------+-------+----------------+--------------
1 | joe | joe#gmail.com | 203-234-2345
2 | jane | jane#gmail.com | 123-456-7890
I have solved it but it feels clumsy and I want to know if there is a better way to do it. Meaning solutions that are either more readable or faster(optimized) or simply best-practice.
Current solution: multiple tables selected, many conditional statements:
SELECT u.userID AS memberid,
u.name AS first_name,
pv1.value AS fname,
pv2.value as lname
FROM users AS u,
profile_values AS pv1,
profile_values AS pv2,
WHERE u.userID = pv1.userID
AND pv1.fid = 3
AND u.userID = pv2.userID
AND pv2.fid = 45;
Thanks for the help!
It's a typical pivot query:
SELECT u.userid,
u.name,
MAX(CASE WHEN pv.fid = 3 THEN pv.value ELSE NULL END) AS email,
MAX(CASE WHEN pv.fid = 45 THEN pv.value ELSE NULL END) AS phone,
FROM USERS u
JOIN PROFILE_VALUES pv ON pv.userid = u.userid
GROUP BY u.userid, u.name
Add "LEFT" before the "JOIN" if you want to see users who don't have any entries in the PROFILE_VALUES table.
I didn't say this, which I should have (#OMG Ponies) but I wanted to use this within a MySQL view. And for views to be editable you're not allowed to use aggregate functions and other constraints. So what I had to do whas use the same SQL query as I had described in the initial question.
Hope this helps someone, adding tag for creating views.