Search for if column has 'a' AND 'b' - sql

Suppose you have two tables... table 1 and table 2.
table 1 columns are name / age / area
table 2 has area / job title
I would like to select area and job title only if the area includes both names 'sarah' and 'Phillip' (has to include BOTH the given names)

One way to do it is a combination of exists, group by having and count:
SELECT area, JobTitle
FROM Table2 t2
WHERE EXISTS
(
SELECT t1.Area
FROM Table1 t1
WHERE t1.Area = t2.Area
AND Name IN('sarah', 'Phillip')
GROUP BY t1.Area
HAVING COUNT(DISTINCT t1.Name) = 2
)

Another method is not quite as flexible as the aggregation method. However, you have two tables, and it might have better performance:
select t2.*
from table2 t2
where exists (select 1 from table1 t1 where t1.area = t2.area and t1.name = 'sarah') and
exists (select 1 from table1 t1 where t1.area = t2.area and t1.name = 'Phillip');
In particular, this can take advantage of an index on table1(area, name).

if you have a unique constraint on table1 for (area, name) and if you have performance problems when using the more general answers, you could experiment with joins - which the DB engine can sometimes optimize more than a correlated subquery:
select t2.*
from table2 t2
join table1 t1a on t1a.area = t2.area and t1a.name = 'sarah'
join table1 t1b on t1b.area = t2.area and t1b.name = 'Phillip';

Related

Compare 2 Tables and return full data

Im struggling with writing a query and infact do not know which query is relevant for the task (Union, Inner/Outer Join etc)
I have a table of data that is revised each week and I need to report on the differences.
i.e if it gets deleted in table 1, table 2 or a field changes.
I have included an image to show the data from the revised table and also what I would like as an output to report on (Ignore the Comments, they are only for reference)
Any help would be appreciated.
I don't believe access supports full outer joins ...
so... we use a left join and a right join and a union along with a case statement.
Select A.*, case when T1.Name=T2.Name and T1.Area=T2.Area then 'In T1 and T2 and Equal'
when T2.Name is null then 'In T1 Only'
when T1.Name is null then 'in T2 Only,omitted in T1'
when T1.Name = T2.Name and T1.Area<> T2.Area then 'In T1 and T2 Different area' from (
Select t1.*, T2.*
FROM table1 T1
LEFT JOIn table2 T2
on T1.Name = T2.Name and T1.Area = T2.Area
UNION
Select t1.*, T2.*
FROM table1 T1
RIGHT JOIN table2 T2
on T1.Name = T2.Name and T1.Area = T2.Area) A
FULL OUTER JOIN to find any rows from table 1 or table 2 and align them whenever possible then you can use a CASE to create the comment column based on the comparison of AREA, or NAME being null.
But MS ACCESS doesn't have FULL JOIN so we need LEFT JOIN UNION RIGHT JOIN.
Also CASE statement is VB syntax, use switch
SELECT
t1.*,
t2.*,
switch(
t2.name IS NULL,'IN TABLE 1 ONLY',
t1.area <> t2.area,'IN TABLE 1 AND 2 SAME NAME BUT AREA DIFFERENT IN TABLE 2',
true,'IN TABLE 1 AND 2 AND EQUAL')
FROM table1 AS t1
LEFT JOIN table2 AS t2
ON t1.name = t2.name
UNION
SELECT
t1.*,
t2.*,
switch(
t1.name IS NULL,'IN TABLE 2 ONLY, OMITTED IN TABLE 1',
t1.area <> t2.area,'IN TABLE 1 AND 2 SAME NAME BUT AREA DIFFERENT IN TABLE 2',
true,'IN TABLE 1 AND 2 AND EQUAL')
FROM table1 AS t1
RIGHT JOIN table2 AS t2
ON t1.name = t2.name

Combine two tables on same columns

I have 2 tables as showen below:
TABLE 1: Name Age Weight(Kilo)
Tom 16 56
Alex 29 89
TABLE 2: Name Age Sex
Tom 16 M
Alex 29 M
What I want to get:
TABLE 3: Name Age Sex Weight(Kilo)
Tom 16 M 56
Alex 29 M 89
I have tried Union/Union All and it doesn't work. Also tried to use Join but it gives me a table with duplicate values. Any idea how to do this?
Assuming your Name/Age values match up exactly between the two tables, a JOIN would be exactly what you're looking for.
select t1.Name, t1.Age, t2.Sex, t1.Weight
from Table1 t1
join Table2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
If there is any possibility that there is no match between the tables, start with the one with the larger number of records, then do a left outer join:
For example, assume Table1 has every person, but Table2 may be missing some:
select t1.Name, t1.Age, t2.Sex, t1.Weight
from Table1 t1
left join Table2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
If you might have records in either table that aren't in the other, a full outer join would work:
select
coalesce(t1.Name, t2.Name) [Name]
,coalesce(t1.Age, t2.Age) [Age]
,t2.Sex
,t1.Weight
from Table1 t1
full join Table2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
Since it doesn't look like you have a PRIMARY KEY
SELECT
t1.*,
t2.Sex
FROM
table1 t1
INNER JOIN
tabel2 t2 on t1.Name = t2.Name and t1.Age = t2.Age
This is most likely still going to cause some duplicates in larger datasets, but I'm assuming you are looking for logic and posted some dummy data.
JOIN is exactly what you need, but you need to join on a unique identifier. In this case, the Name column is unique for those two records, but usually JOINs are done on generated IDs such as CustomerID or ClientID. Like others have posted, you can use the other columns in conjunction with the Name column to ensure you don't get duplicates by adding those columns in the ON section of the JOIN clause.
SELECT t1.Name, t1.Age, t2.Sex, t1.Weight
FROM Table1 t1
INNER JOIN Table2 t2
ON (t1.Name = t2.Name)
I suggest adding a unique identifier as a primary key so JOINs are a lot easier to do in the future.
SELECT t1.*,t2.Sex
FROM table1 t1 LEFT JOIN table2 t2 ON t1.Name=t2.Name

Tsql select from related table with AND condition

I've two related tables:
Table1
Id
-----
1
2
3
Table2
Id Feature
--------------
1 Car
1 Moto
1 Camper
2 Moto
2 Scooter
3 Apple
I want to select Ids which have, for example, both 'Car' AND 'Moto'.
So in the example i want to get only Id = 1.
Use the INTERSECT operator:
select id from table2 where feature = 'Car'
intersect
select id from table2 where feature = 'Moto'
This:
WITH features AS
(
SELECT feature
FROM (
VALUES
('Car'),
('Moto')
) q (feature)
)
SELECT *
FROM table1 t1
WHERE NOT EXISTS
(
SELECT feature
FROM features
EXCEPT
SELECT feature
FROM table2 t2
WHERE t2.id = t1.id
)
or this:
SELECT *
FROM table t1
WHERE (
SELECT COUNT(*)
FROM table2 t2
WHERE t2.id = t1.id
AND t2.feature IN ('Car', 'Moto')
) = 2
Which query is more efficient depends on how many records you have in both tables and how many matches there are.
This select does two LEFT OUTER JOINs to table2 (one based on 'Car' and the other based on 'Moto') and makes sure that each JOIN returned a result. The DISTINCT ensures that you get each ID only once.
SELECT DISTINCT t1.id
FROM table2 t2
LEFT OUTER JOIN table2 t2_2 ON t2.id = t2_2.id AND t2_2.feature = 'Moto'
WHERE t2.feature = 'Car'
AND t2_2.id IS NOT NULL
Edit: Removed join to table1 since it really isn't needed.

SQL Join Question

I have an interesting question for an SQL Join. I have 2 tables, examples below:
Table1: ID (int), Value(string)
Table2: ID (int), ForeignID(int), (Value)
The field ForeignID in Table2 is the foreign key of the ID in Table1. For a given entry in Table1, I have multiple entries in Table2 as follows:
Table1:
ID, Value
0, "Hello World"
1, "Bonjour"
Table2:
ID, ForeignID, Value
0, 0, "First entry"
1, 0, "Second entry"
2, 1, "Third entry"
If I do an inner join such as
SELECT Table1.Value, Table2. Value FROM
Table1 INNER JOIN Table2 ON Table1.ID = Table2.ForeignID
I would get
Hello world, First entry
Hello world, Second entry
Bonjour, Third entry
Is there a way to only get the TOP entry in Table2 such as:
Hello world, First entry
Bonjour, Third entry
This works too:
SELECT Table1.value
, Table2.value
FROM Table1
INNER JOIN Table2 ON Table1.id = Table2.foreignID
INNER JOIN (
SELECT MIN(ID) AS ID, ForeignID
FROM Table2
GROUP BY ForeignID
) MinID ON Table2.foreignid = MinID.foreignid
AND Table2.id = MinID.id
SELECT
t1.Value,
(
SELECT TOP 1 t2.Value FROM Table2 t2
WHERE t2.ForeignID = t1.ID
ORDER BY t2.ID ASC
)
FROM Table1 t1
SELECT Table1.Value,
(SELECT TOP 1 Table2.Value
FROM Table2
WHERE Table2.ForeignID = Table1.ID)
FROM Table1
Since you tagged SQL, here is the ANSI SQL query (which should work on SQL Server 2005+) :
WITH TT (ID, ForeignID, Value, N) AS (
SELECT ID, ForeignID, Value,
ROW_NUMBER() OVER(PARTITION BY ForeignID ORDER BY ID)
FROM Table2
)
SELECT T1.Value, T2.Value
FROM Table1 T1
INNER JOIN TT T2
ON T1.ID = T2.ForeignID
AND T2.N = 1;
It uses a Common Table Expression and a windowing function.
Here is another variation that makes sure that table2 in joined to table1 on the proper key.
SELECT t1.Value,
t2.Value
FROM Table1 t1
INNER JOIN Table2 t2
ON t2.ForeignID = (SELECT MIN(sub.ForeignID)
FROM Table2 sub WHERE sub.ForeignID = t1.ID)
Edit, actually, scratch that. Tamila's answer looks better to me.
If you can add a boolean is_first flag to your table2 then things become a lot easier and this would do the job for you:
SELECT table1."value", table2."value"
FROM table1
INNER JOIN table2 ON table1.id = table2.foreign_id
WHERE table2.is_first = true
I don't know if Daniel's, cgatian's or Leons' answers will work for your database. I'm on Postgres and it doesn't work for me.

query related to in clause

I have two tables:
table 1
fid
field
queryorder
table 2
fid
field
name
fid and field are same in both tables. I want a query like
select fid
from table 1
where field in table 1 corresponding to name = dell
and should not have queryorder = 1
Your question is not clearly worded, but if I'm reading it right, all you want to show is the fid from table 1, where the "name" field in table2 = dell, and the "queryorder" field from table 1 is not equal to "1".
SELECT
table1.fid
FROM
table1
INNER JOIN
table2
ON
table1.fid = table2.fid
AND table1.field = table2.field
WHERE
table2.name = 'dell'
AND table1.queryorder <> 1
Small piece of advice: you should not name a field "name" -- that's a keyword, and will cause you headaches down the road.
SELECT fid FROM table1 WHERE name='dell' AND fid NOT IN (SELECT fid FROM table2 WHERE queryorder != 1)
It's very hard to tell what you're asking from the question, there. This will give you all fids where the name in table1 is 'dell' and the queryorder in table2 is not 1.
This looks like it's really just a join, but I can't tell what you're looking for exactly..
SELECT DISTINCT(fid) FROM Table1 T1
JOIN Table2 T2 ON T1.fid = T2.fid
WHERE t2.queryOrder != 1 AND T1.name = 'DELL'
select t1.fid
from table1 t1, table2 t2
where t1.fid = t2.fib
AND t1.field = t2.field
and t2.name= 'dell'
and t1.queryorder <> 1