sql query to print users who have different passwords and its count - sql

I've a oracle table values as below.
UserName Password Application
============== ================ ===============
John cat gmail
John cat ldap
John dog yahoo
John dog fusion
Rick boat oracle
Rick mat gmail
Rick boat yahoo
Joe lilly gmail
Joe lilly yahoo
Joe lilly oracle
I want to query users who have differnt passwords and also its count. I want to have the following as a result.
John cat 2
John dog 2
Rick boat 2
Rick mat 1

SQL Fiddle
Query 1:
WITH password_counts AS (
SELECT DISTINCT
UserName,
Password,
COUNT( DISTINCT Password ) OVER ( PARTITION BY UserName ) AS number_of_passwords,
COUNT( Password ) OVER ( PARTITION BY UserName, Password ) AS count_per_password
FROM SecurityHole
)
SELECT UserName,
Password,
count_per_password
FROM password_counts
WHERE number_of_passwords > 1
ORDER BY UserName, Password
Results:
| USERNAME | PASSWORD | COUNT_PER_PASSWORD |
|----------|----------|--------------------|
| John | cat | 2 |
| John | dog | 2 |
| Rick | boat | 2 |
| Rick | mat | 1 |

The trick, of course, is knowing how to combine the two parts of the query:
SELECT user_password.UserName, user_password.Password, COUNT(*)
FROM user_password
JOIN (SELECT UserName
FROM user_password
GROUP BY UserName
HAVING COUNT(DISTINCT Password) > 1) multiple_passwords
ON multiple_passwords.UserName = user_password.UserName
GROUP BY user_password.UserName, user_password.Password
ORDER BY user_password.UserName
(Have a working SQL Fiddle demo!)
The sub-select (inner query) finds UserNames with more than one password (and gets unique rows, too). Outside of that, it's a standard "count of times entry is reused" query.
(And by the way, I hope these aren't real passwords... #shudders#)

this should work:
SELECT username,password,COUNT(*)
FROM t
WHERE username IN (SELECT username FROM t GROUP BY username HAVING COUNT(DISTINCT password>1))
GROUP by username,password
you can optimize it if you'll use with clause to prevent the table from being read twice.

Related

VSQL: Concatenate two values in same column from same table

I have a table that looks like the following:
email | first_name
----------------------+------------
------#diffem.com | Matthew
------#email.net | Susan
------#email.net | Thomas
------#email.com | Donald
------#email.com | Paula
I.e. I have records where there is only one value (name) per key (email), but in other instance I have two values per key.
I want the output to look like this:
email | first_name
----------------------+-----------------
------#diffem.com | Matthew
------#email.net | Susan and Thomas
------#email.com | Donald and Paula
I have tried the following, but it is not working due to grouping by an aggregate function:
CREATE TABLE user.table1 AS
(
select distinct email
, case when email_count = 1 then first_name
when email_count = 2 then (MIN(first_name))||' and '||MAX(first_name))
else null end as first_name_grouped
FROM (
SELECT email
, first_name
, count(email) over (partition by email) as email_count
FROM table
)
x
)
;
I've also tried partitioning by email, putting the two names into different columns and then concatenating that, but am ending up with blanks in my output table (see below)
email | name1 | name 2
----------------------+--------+-------
------#email.net | Susan | null
------#email.net | null | Donald
Is there a way to do this in SQL, without creating two separate name columns? Thanks in advance.
What you are trying to accomplish could be done in MYSQL like
SELECT email, GROUP_CONCAT(first_name)
FROM table
GROUP BY email
There is similar function in MS SQL server called STRING_AGG() , you can see more here https://database.guide/mysql-group_concat-vs-t-sql-string_agg/

Reorganize multiple rows in a new table with more columns

I have a table that looks like that:
+----------+----------+----------+----------+--------------------------+
| Club | Role | Name | Lastname | Email |
+----------+----------+----------+----------+--------------------------+
| Porto | 1 | Peter | Pan | peter.pan#mail.com |
| Porto | 2 | Michelle | Obama | michelle.obama#mail.com |
| Monaco | 1 | Serena | Williams | serena.williams#mail.com |
| Monaco | 2 | David | Beckham | david.beckham#mail.com |
+----------+----------+----------+----------+--------------------------+
and i want to get a table like that:
+----------+-----------------+-----------------+---------------------------------+-----------------+-----------------+---------------------------------+
| Club | Role 1 Name | Role 1 Lastname | Role 1 Email | Role 2 Name | Role 2 Lastname | Role 2 Email |
+----------+-----------------+-----------------+---------------------------------+-----------------+-----------------+---------------------------------+
| Porto | Peter | Pan | peter.pan#mail.com | Michelle | Obama | michelle.obama#mail.com |
| Monaco | Serena | Williams | serena.williams#mail.com | David | Beckham | david.beckham#mail.com |
+----------+-----------------+-----------------+---------------------------------+-----------------+-----------------+---------------------------------+
where the persons with different roles in each club puts in the same row.
I would ideally like to find a way to do that in Excel, but i am not sure if its possible. If not, SQL code would also help a lot.
Here is what I could come up with for an excel formula. Hopefully it can push you in the right direction.
This formula is assuming that your first table exists at the range A1:E5 and the second table exists at the range G1:M3. It is also assuming that the second table's column names are just repeating without the Role number attached to the front of it (same as the first table). This formula is an array formula, so you have to make sure to do CTRL+SHIFT+ENTER when inputting it.
{=INDEX($A$2:$E$5,
MATCH(1,($G2=$A$2:$A$5)*((FLOOR((COLUMN() - COLUMN($H$1) ) / 3,1) + 1)=$B$2:$B$5),0),
MATCH(H$1,$A$1:$E$1,0))}
The first part is using the INDEX forumla which pulls data from the range suppled ($A$2:$E$5) based on the row and column numbers supplied by the following MATCH formulas.
The first MATCH is supplying the row number for when the result of the lookup array section is equal to 1. I am checking two conditions, the first is to check for the "Club" name ($G2=$A$2:$A$5) and the second is to check for which "Role" we are currently on ((FLOOR((COLUMN() - COLUMN($H$1) ) / 3,1) + 1). This is using the FLOOR function to round the result down to the whole number and dividing by the number of columns (3 in this case: Name, Lastname, and Email).
The final MATCH is pulling the column number based on the header names from both tables. If you wanted to incorporate the changing names of the roles in the column headers, you could change this part to something like this:
{=INDEX($A$2:$E$5,
MATCH(1,($G2=$A$2:$A$5)*((FLOOR((COLUMN() - COLUMN($H$1) ) / 3,1) + 1)=$B$2:$B$5),0),
MOD(COLUMN() - COLUMN($H$1),3) + 3)}
I am adding 3 to the end of the mod because of the original range that was selected for table 1. The columns that we want to pull start at location 3 in the range.
If you want to do this in Oracle Sql, there's a nice approach in analytical sql.
To convert/swap rows to columns or columns to rows, we can use Pivot or Unpivot operators.
In you example use below query to covert data as you like,
select * from
(
with all_roles as
(select 1 role from dual union all
select 2 role from dual),
ddata as
(select 1 c_role, 'porto' club, 'peter' fname,'pan' lname,'peter.pan#mail.com' email from dual union all
select 2 c_role, 'porto' club, 'Michelle' fname, 'Obama' lname,'michelle.obama#mail.com' email from dual union all
select 1 c_role, 'monaco' club, 'Serena' fname, 'Williams' lname,'serena.williams#mail.com' email from dual union all
select 2 c_role, 'monaco' club, 'David' fname, 'Beckham' lname,'david.beckham#mail.com' email from dual )
(select role, club, fname,lname, email from ddata,all_roles
where all_roles.role=ddata.c_role)) all_data
pivot (
max(fname) fname,
max(lname) lname,
max(email) email
for role in ( 1 role1, 2 role2 )
)
order by club;

SQL Query to get mapping of all users to their logins

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

Postgres Many to many mapping sql query

Postgresql Database
Table User
-----------
ID | Name
1 | John
2 | Bob
3 | Sarah
Table Photo
-------------
ID | Caption
1 | Vacation
2 | Birthday
3 | Christmas
Table Comment
--------------
ID | User ID | Photo ID| Text
1 | 1 | 1 | Mexico Looks Great
2 | 2 | 1 | Sure Does
3 | 3 | 1 | Too Hot
4 | 1 | 2 | Look at that cake
5 | 3 | 2 | No ice cream?
6 | 1 | 3 | So Happy
Desire: I want to get all the photos that ONLY John(1) and Sara(3) commented on.
How do I build a SQL query that looks for photos that only have comments from user #1 and user #3, I want to EXCLUDE results where more(or less) than those two commented on.
The clearest and most readable way, is the Photos containing comments by:
User1 Intersect User2 Except Any other user
This SQL Fiddle and query will return that:
SELECT *
FROM Photo
WHERE ID IN (
SELECT "Photo ID" FROM Comment WHERE "User ID" = 1
INTERSECT
SELECT "Photo ID" FROM Comment WHERE "User ID" = 3
EXCEPT
SELECT "Photo ID" FROM Comment WHERE "User ID" NOT IN (1, 3)
)
lets do three joins, one for john, one for sara, one for everyone else. Then we'll limit what we get back with the where clause.
select p.*
from photo p
left join comment john on john.photo_id=p.photo_id and john.user_id=1
left join comment sara on sara.photo_id=p.photo_id and sara.user_id=3
left join comment everyone_else on everyone_else.photo_id=p.photo_id and everyone_else.user_id<>3 and everyone_else.user_id<>1
where
everyone_else.id is null
and john.id is not null
and sara.id is not null
There are a couple of ways to do this. One is to use count with case:
select photoid
from comment
group by photoid
having count(distinct userid) = 2
and count(case when userid not in (1,3) then 1 end) = 0
SQL Fiddle Demo
Basically, make sure 2 users have commented and then make sure only user 1 or 3 commented.
You could use an intersection to find only the common photos, which would exclude photos commented by John but not Sarah, or vice versa
select photo_id from comment where user_id = 1
intersect
select photo_id from comment where user_id = 3

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.