My SQLServer table 'Users' is like
User Usertype
---------------------------
Mike S
Sally S
Alan S
Sally H
Alan S
Mike S
Mike H
I am trying to build a query on this table which should return the user that has no 'H' usertype. For e.g., the above table should return 'Alan' as this user has no 'H' pair, while Mike and Sally has at least one 'H'.
Kindly help
Group by the user and then check how many H types each user has. That number must be 0 for the ones you are looking for.
select [user]
from your_table
group by [user]
having sum(case when usertype = 'H' then 1 else 0 end) = 0
Try this.It return the result 'Alas'.
select distinct User from Users where User not IN(
select a.User from Users a join Users b
on a.User=b.User and a.Usertype!=b.Usertype)
Demo SQL FIDDLE: http://sqlfiddle.com/#!2/2f175/24
Related
I'm a novice when it comes to SQL, so forgive me if this is a dumb question.
I have 2 tables, one with a list of users, and one that holds email history data.
Users Table:
userID fName lName ...
1 John Smith
2 Jane Doe
3 Kevin Cooper
Email History Table:
emailID userID subject sendDate ...
1 6 welcome 2020-10-17
2 3 hello 2020-10-20
3 7 welcome 2020-10-23
I am wanting to do some sort of select statement that would compare every customer in table 1, to every email in table 2 based on some sort of search query (in this case where subject = "hello" and sendDate = "2020-10-20" and would return something like this:
Returned Query:
userID fName lName ... emailSent?
1 John Smith ... No
2 Jane Doe ... No
3 Kevin Cooper ... Yes
One option uses exists and a correlated subquery:
select u.*,
exists (
select 1
from emailhistory eh
where eh.userid = u.userid and eh.subject = 'hello' and eh.senddate = '2020-20-20'
) emailSent
from users u
This gives you 0/1 values in column emailSent, where 1 indicates that a match exists. As compared to the left join approach, the upside is that it does not "multiplies" the user rows if more than one match is found in the history table.
For performance, consider an index on emailhistory(userid, subject, senddate).
You can left join the email table on, putting your date and subject criteria in the where clause:
SELECT
u.userid,
u.fname,
u.lname,
case when eh.emailid is null then 'No' else 'Yes' end as emailsent
FROM
users u
LEFT JOIN
emailhistory eh
ON
u.userid = eh.emailid AND
eh.subject = 'hello' AND
eh.senddate = '2020-10-20'
This conceptually filters the email table down to just that subject and day, then joins those records onto the users table. You get every row from users and only rows from emailhistory that match on userid, and also had that subject/date. You can then examine whether the emailid (a key of the join) is null or not; the only way it can be null is if no email was sent to that user on that date with that subject
Flat Table Structure
DudeTable
ID Dude NextDoorDude
1 Jim Nick
2 Mike Mike
so if I write a query to compare them, I'd use
SELECT count(*) FROM DudeTable WHERE Dude = NextDoorDude
Normalized Form
DudeTable
ID DudeType Name
1 person Jim
1 neighbor Nick
2 person Mike
2 neighbor Mike
How do I write a query to compare two rows and get the similar result as I did for flat table?
This could be a simple scenario but I have no idea... Googling didn't help me... Hope someone here would shed some light
One method uses aggregation and a having clause:
select id
from dudetable t
group by id
having max(case when dudetype = 'person' then name end) = max(case when dudetype = 'neighbor' then name);
Another method uses join:
select dp.id, dp.name
from dudetable dp join
dudetable dn
on dp.id = dn.id and
dp.dudetype = 'person' and
dn.dudetype = 'neighbor' and
dp.name = dn.name
Hi friends from Stack Overflow. I am trying to run a query in MS Access, i just want one record per ID randomly, but I am getting all.
I tried with distinct is not working, and I try with top, didn't work either.
this is my table below originaldata
ID HotelName Role Email
__________________________
1 bandb admin test1#email.com
1 bandb admin test2#email.com
1 bandb admin test3#email.com
1 bandb user myuser#email.com
2 myhtl admin myhotel#email.com
3 ben admin ben#test.com
3 ben user ben2#test.com
4 moon admin moon#moon.com
4 moon admin moon#moon2.com
I want to get the below results
ID HotelName Role Email
__________________________
1 bandb admin test1#email.com
2 myhtl admin myhotel#email.com
3 ben admin ben#test.com
4 moon admin moon#moon.com
SELECT *
FROM OriginalData
WHERE (((OriginalData.[Role])='admin') AND ((OriginalData.[ID]) In (Select Distinct [ID] from [OriginalData] where [Role] = 'Admin' )));
Thank you for your time and help
SELECT ID, min(HOTELNAME), min(ROLE), min(EMAIL)
from OriginalData
group by ID
Assuming you would be OK with displaying the "minimum" email address per each hotel group, then the following query should work:
SELECT od1.ID, od1.HotelName, od1.Role, od1.Email
FROM OriginalData od1
INNER JOIN
(
SELECT ID, Hotel, MIN(Email) AS min_email
FROM OriginalData
WHERE Role = 'admin'
GROUP BY ID, Hotel
) od2
ON od1.ID = od2.ID AND
od1.Hotel = od2.Hotel AND
od1.Email = od2.min_email
WHERE
od1.Role = 'admin'
ORDER BY
od1.ID;
Edit:
Coincidentally, for the exact data you showed us, you might also be able to simplify to:
SELECT ID, Hotel, Role, MIN(Email) AS Email
FROM OriginalData
WHERE Role = 'admin'
GROUP BY ID, Hotel, Role;
However, this only works because all the columns you want to appear are either aggregates or constants. If you had other columns specific to a matching minimum row, this would not work.
Well this is easy but with a twist (notice the the TOP 1...it will return just one record
SELECT TOP 1 *
FROM OriginalData
WHERE OriginalData.[Role])='admin'
The problem is that in order to get Random you need to use something for randomize it for some value ...here lets take ID
So the SQL will be :
SELECT TOP 1 *
FROM OriginalData
WHERE OriginalData.[Role])='admin' AND ID = Clng(Rnd() * Dmax("ID","OriginalData")
I have a dataset, myTable, that looks like this:
username saveType
Alice auto
Alice auto
Alice manual
Alice manual
Bob auto
Bob auto
Bob auto
Bob auto
I want to count how many auto and manual saveType's were found per user.
Ideally I'd like the query result to look like this:
username AutoCount ManualCount
Alice 2 2
Bob 4 0
But when I run this query:
SELECT username, COUNT(saveType="auto") AutoCount, COUNT(savetype="manual") ManualCount
FROM myTable
GROUP BY username
I get this instead:
username AutoCount ManualCount
Alice 4 4
Bob 4 4
The db is data world. Any explanation for what's going on here would be helpful! Thanks!
Try below using CASE WHEN
SELECT
username,
COUNT(case when saveType='auto' then 1 end) AutoCount,
COUNT(case when savetype='manual' then 1 end) ManualCount
FROM myTable
GROUP BY username
Replace COUNT with SUM in your current query and it should work:
SELECT
username,
SUM(saveType='auto') AutoCount,
SUM(savetype='manual') ManualCount
FROM yourTable
GROUP BY username;
Demo
The problem with COUNT(saveType='auto') is that the expression inside will either evaluate to 0 (false) or 1 (true). But, in both cases COUNT will count 1 for them. SUM gets around this by effectively ignoring zero values.
You can try also this query :
select r.username, t1.AutoCount, t2.Manualcount from
yourtable r inner join (select username, count(saveType) autoCount from yourtable where saveType='auto' group by username) t1
on t1.username = r.username
inner join (select username, count(saveType) ManualCount from yourtable where saveType ='manual' group by username) t2
on t2.username = r.username
Hope this can help you.
I have 2 databases. I want to write a query that will pull data from both and tie them into the same result.
user database:
id username group
1 steve group1
2 joe group1
3 tom group2
data database:
id userid fieldname fieldresult
1 2 phone 867-5309
2 2 address 123 elm st
3 1 address 666 park avenue
If I just want steve's address, I could write:
select user.username, data.fieldresult from user, data where user.id = data.userid and data.fieldname = 'address' and user.username = 'steve';
The result would be:
username fieldresult
steve 666 park avenue
But what if I want all of the fieldresults for joe in a single row? Is that possible to do from the query itself, or do I have to handle that in code?
Basically, I'd like to see:
username phone address
joe 867-5309 123 elm st
Is this wishful thinking? I wouldn't even need "phone" and "address" as the headers, as long as I could get their values in the same result.
NOTE: I'm working with an existing database and this is how the information is currently stored.
EDIT:
Also, I need to do this on a much larger basis. Instead of querying by the username, can I get this information in the same way for each user in an entire group.
Try
select a.username,
b.fieldresult as phone,
c.fieldresult as address
from #user a
left join #data b on a.id=b.userid and b.fieldname='phone'
left join #data c on a.id=c.userid and c.fieldname='address'
where a.id = 2
You can try pivoting contact info in datadb table and then join it with user
select * from userdb..[user] u join
(
select userid,phone, address from
(
select userid,fieldname,fieldresult from datadb..data
) as a pivot
(
max(fieldresult) for fieldname in (phone, address)
) piv ) as a
on a.userid = u.id
this would result in something as follows.
id username group userid phone address
1 steve group1 1 NULL park aven
2 joe group1 2 867-5309 123 elm st
The two tables i used are user_ and data.
Hope,this might help you
DECLARE
user_name user_.username%type:='joe';
phone_no data.fieldresult%type;
full_address data.fieldresult%type;
user_id user_.id%type;
CURSOR c_name IS select * from data;
result c_name%rowtype;
BEGIN
select id into user_id from user_ where username=user_name;
open c_name;
LOOP
fetch c_name into result;
IF ( result.userid=user_id AND result.fieldname='phone') THEN
phone_no:=result.fieldresult;
END IF;
IF(result.userid=user_id AND result.fieldname='address') THEN
full_address:=result.fieldresult;
END IF;
EXIT when c_name%NOTFOUND;
END LOOP;
close c_name;
dbms_output.put_line(user_name||' '||phone_no||' '||full_address);
END;
/
OUTPUT: joe 867-5309 123 elm st