Select from 1 table where conditions are in another table? - sql

Here is my table in my database:
table1 table2
---------|-------- --------|
UserID |Type UserID |
---------|-------- --------|
user1 |Busy user1 |
user2 |Free user2 |
user3 |Free user3 |
user4 |Busy user4 |
I would like to select all the userID from table1 where the Type=Free. The only correlation from one table to another is that they have the same UserID in both tables.
What I have so far is :
SELECT UserID
FROM Data.Users
INNER JOIN Data.UserType
ON Data.Users.UserID=Data.UserType.UserID
This only gives me back ALL the userID where the UserID from table 1 = UserID from table 2.
I would like to be able to make it also check for the user type. Something like
SELECT Username FROM Data.Users WHERE TABLE2.UserID = TABLE1.UserID AND
TABLE2.UserType = "free"
I'm new to SQL so I don't think I'm Googling the right thing as well

So your query is working you just need to filter it:
SELECT Data.Users.Name
FROM Data.Users
INNER JOIN Data.UserType
ON Data.Users.UserID=Data.UserType.UserID
WHERE Data.UserType.Type = 'Free'

You have to ensure you are first selecting the data that you want, in this case "Type". So that's all we need to be concerned with when selecting information. However, for illustration purposes (and general good etiquette) lets also select the userID, but we'll take this from table1.
So we want to select Type from Table 2, and UserID from table 1, but where UserID is the same on both tables.
To do what we need to do the following:
SELECT two.Type, one.UserID FROM table2 two INNER JOIN table1 one ON two.UserID = one.UserID
This selects the information, from table2 and we assign it the reference two. Then we join table1 and assign the reference one. We can then grab the requested information in the select using the references we assigned, whilst also ensuring the data is joined where the two tables have identical values.
The above example will select all values where the userID's match, and is used for illustration purposes. Then, to narrow it down, all you have to do is specify the WHERE value on top of this. So:
SELECT two.Type, one.UserID FROM table2 two INNER JOIN table1 one ON two.UserID = one.UserID WHERE two.Type = "Free"

Related

Remove all instances of a record if condition is met

Im trying to remove all instances of a record if the value in the flag field is 4. (this means they have unsubscribed from the email list)
Sample data:
Customer# Email Name CustomerType Flag
001 email#email.com Bob Vet 1
001 email#email.com Bob Med 2
001 email#email.com Bob Pod 4
So since there is an instance that this record has a Flag of 4, all 3 should be removed from this query. They don't need to actually be deleted from the database, I just don't need the data to come up in my query. How do I approach this?
Assuming that the customer number is what links the records together, you can use a not exists clause:
select *
from tbl t1
where not exists (select *
from tbl t2
where t2.[Customer#] = t1.[Customer#]
and t2.Flag = 4)
Three approaches.
use Not exists
use a where not in
use a join
Below is the join: Sstan provided the not exists and Gordon more or less provided the where in but change to not in and a select and you'd have it as well.
Without table size volume of translations and index information I can't say which would offer the best performance though the not exists is the strong favorite.
SELECT A.*
FROM TableName A
LEFT JOIN TableName B
on A.Customer# = B.Customer#
and B.Flag = 4
WHERE B.Customer# is null
This does a self join but only to a set of records that are flagged as 4. it then excludes those records which have a match; returning only customer#'s which don't have a 4.
Here is one method:
delete from sample
where customer# in (select customer# from sample as s2 where flag = 4);
EDIT:
You can readily adapt this to a select:
select s.*
from sample s
where customer# not in (select customer# from sample as s2 where flag = 4);

SQL query (Join without duplicates)

I have tables users and topics. Every user can have from 0 to several topics (one-to-many relationship).
How I can get only those users which have at least one topic?
I need all columns from users (without columns from topics) and without duplicates in table users. In last column I need number of topics.
UPDATED:
Should be like this:
SELECT user.*, count(topic.id)
FROM ad
LEFT JOIN topic ON user.id = topic.ad
GROUP BY user.id
HAVING count(topic.id) > 0;
but it takes 0 result. But it should not be 0.
Firstly you need to have your two tables, because you have left limited information about your table structure I will use an example to explain how this works, you should then be able to easily apply this to your own tables.
Firstly you need to have two tables (which you do)
Table "user"
id | name
1 | Joe Bloggs
2 | Eddy Ready
Table "topic"
topicid | userid | topic
1 | 1 | Breakfast
2 | 1 | Lunch
3 | 1 | Dinner
Now asking for a count against each user is done using the follwing;
SELECT user.name, count(topic.topicid)
FROM user
INNER JOIN topic ON user.id = topic.userid
GROUP BY user.name
If you use a left join, this will include records from the "user" table which does not have any rows in the "topic" table, however if you use an INNER JOIN this will ONLY include users who have a matching value in both tables.
I.e. because the user id "2" (which we use to join) is not listed in the topic table you will not get any results for this user.
Hope that helps!
use inner join and distinct
select distinct user_table.id
from user_table
inner join topics_table on topic_table.user_id = user_table.id
select u.id
, u.name
, count(b.topicName)
from user u
left join topic t on t.userid = u.id
group by u.id, u.name
You can select topic number per user and then join it with user data. Something like this:
with t as
(
select userid, count(*) as n
from topic
group by userid
)
SELECT user.*, t.n
FROM user
JOIN t ON user.id = t.userid

Update multiple row values to same row and different columns

I was trying to update table columns from another table.
In person table, there can be multiple contact persons with same inst_id.
I have a firm table, which will have latest 2 contact details from person table.
I am expecting the firm tables as below:
If there is only one contact person, update person1 and email1. If there are 2, update both. If there is 3, discard the 3rd one.
Can someone help me on this?
This should work:
;with cte (rn, id, inst_id, person_name, email) as (
select row_number() over (partition by inst_id order by id) rn, *
from person
)
update f
set
person1 = cte1.person_name,
email1 = cte1.email,
person2 = cte2.person_name,
email2 = cte2.email
from firm f
left join cte cte1 on f.inst_id = cte1.inst_id and cte1.rn = 1
left join cte cte2 on f.inst_id = cte2.inst_id and cte2.rn = 2
The common table expression (cte) used as a source for the update numbers rows in the person table, partitioned by inst_id, and then the update joins the cte twice (for top 1 and top 2).
Sample SQL Fiddle
I think you don't have to bother yourself with this update, if you rethink your database structure. One great advantage of relational databases is, that you don't need to store the same data several times in several tables, but have one single table for one kind of data (like the person's table in your case) and then reference it (by relationships or foreign keys for example).
So what does this mean for your example? I suggest, to create a institution's table where you insert two attributes like contactperson1 and contactperson2: but dont't insert all the contact details (like email and name), just the primary key of the person and make it a foreign key.
So you got a table 'Person', that should look something like this:
ID INSTITUTION_ID NAME EMAIL
1 100 abc abc#inst.com
2 101 efg efg#xym.com
3 101 ijk ijk#fg.com
4 101 rtw rtw#rtw.com
...
And a table "Institution" like:
ID CONTACTPERSON1 CONTACTPERSON2
100 1 NULL
101 2 3
...
If you now want to change the email adress, just update the person's table. You don't need to update the firm's table.
And how do you get your desired "table" with the two contact persons' details? Just make a query:
SELECT i.id, p1.name, p1.email, p2.name, p2.email
FROM institution i LEFT OUTER JOIN person p1 ON (i.contactperson1 = p1.id)
LEFT OUTER JOIN person p2 ON (i.contactperson2 = p2.id)
If you need this query often and access it like a "table" just store it as a view.

Link one table to another through two columns in SQL

So I have two Tables. The first are Names and their qualifications:
Users:
Name Qualification
---------------------
User1 QualA
User1 QualB
User1 QualC
User2 QualA
User2 QualD
Then a Second table that links two qualifications from the first to another attribute:
Attributes:
Attribute Qual1 Qual2
------------------------
Attr1 QualA QualC
Attr2 QualB QualC
Attr3 QualA QualD
Attr4 QualB QualD
Now I want to query the data so I get something like this in return:
User Attribute
------------------
User1 Attr1
User1 Attr2
User2 Attr3
So if the Name has the two qualifications required for the Attribute, they can be associated together.
I would use this:
select
name, attribute
from
users inner join attributes
on users.qualification in (attributes.qual1, attributes.qual2)
group by attribute, name
having count(*)=2
I am trying to join each qualification for each user with attributes tables, based on any of the qualifications needed for the attribute. Then I'm grouping by attribute and name and counting the rows.
If a combination of username and attribute has 2 rows, it means that the user has two qualifications for the attribute, and we have to show it.
I had to produce a very similar query, however in my scenario Individuals or Users could be issued with the same Qualification more than once. Hence I had to come with something a bit more complicated than fthiella's solution.
The query I came up with is as follows:
SELECT
j2.name,
Qualification1,
Qualification2,
t3.Attribute
FROM
(SELECT
t1.name,
t1.qualification AS Qualification1,
J1.qualification AS Qualification2,
Rank() over (Partition BY t1.name, t1.qualification ORDER BY t1.qualification, J1.qualification) AS rank1,
Rank() over (Partition BY t1.name, J1.qualification ORDER BY J1.qualification, t1.qualification) AS rank2
FROM
Users t1
LEFT JOIN
(SELECT
t2.name,
t2.qualification
FROM
Users t2) J1
ON
t1.name = J1.name) J2
LEFT JOIN
Attributes t3
ON
t3.Qual1 = Qualification1
AND t3.Qual2 = Qualification2
WHERE
rank2 <= rank1
AND t3.Attribute IS NOT NULL
Basically I'm joining the table Users upon itself, listing all qualification combinations for each user without duplications. This then allows us to do a simple join of the Attributes table.
Of course if your not working with Sql server 2005 or later than the Rank function won't be available to you.

Replace id with string in SQL view

I have two tables...
groupid membership_list managerid
-------------------------------------
0 /0//1//2/ 2
1 /2/ 2
userid username
------------------
0 ben
1 tom
2 dan
I'd like to display a table to for example the user 'ben' that is a list of the groups they are a member of that looks like this...
groupid membership_list managername
---------------------------------------
0 /0//1//2/ dan
.. so basically replacing 'manager_id' with the username for that id. I've been hacking away at this but I can't work it out - my SQL skills are clearly a bit lacking - how can I do this?
SELECT groupid, membership_list, managerid FROM blah WHERE membership_list LIKE '%/?/%'
... is about as far as I've got.
SELECT t1.groupid, t1.membership_list, t2.username
FROM table1 t1
INNER JOIN table2 t2 ON t1.managerid = t2.userid
That should do it. Or am I missing something here??
SELECT A.groupid, A.membership_list, B.managername FROM table1 A, table2 B WHERE A.managerid = B.userid and membership_list LIKE '%/?/%'
you need to break out membership_list column into a new table:
changed table: Groups
groupid
managerid
table users
userid
username
new table: UserGroups
groupid
userid
you can then do this:
SELECT
*
FROM Users u
INNER JOIN UserGroups ug On u.userid=ug.userid
INNER JOIN Groups g ON ug.groupid=g.groupid
WHERE u.Name='Ben'
to find all of Ben's groups.
If you don't want to modify your tables, you will need a split function that will convert the multiple values in membership_list into rows. You have not mentioned the actual database you are working on and a split function is dependent on knowing that.