SQL for 2 tables - sql

I have these 2 tables:
Table A
Country State
-----------------
US OH
US FL
US WA
Table B
State LastVisitDate City
----------------------------------
OH 15/10/2019 Bedford
FL 10/12/2019 Bell
WA 20/09/2019 Perth
Table A can be linked with table B by field "State".
What would be the query to get the latest (last visit date) in country=US, doesn't matter which state, e.g.:
US,10-12-2019,FL,Bell
I tried inner join but couldn't make it work.

Always try to explain your question with sample data and query you tried for.
Here is query with some sample data:
CREATE TABLE A
(
COUNTRY VARCHAR(10),
State VARCHAR(10)
);
INSERT INTO A VALUES('US','OH'),
('US','FL'),
('AU','WA');
CREATE TABLE B
(
State VARCHAR(10),
LastVisitDate DATE,
City VARCHAR(20)
);
INSERT INTO B VALUES
('OH','2019-10-15','Bedford'),
('FL','2019-12-10','Bell'),
('WA','2019-09-20','Perth');
Expected Result:
US,10-12-2019,FL,Bell
Query:
SELECT a.COUNTRY,b.LastVisitDate,b.State,b.City
FROM A
INNER JOIN B ON a.State = b.State
WHERE a.COUNTRY = 'US'
ORDER BY b.LastVisitDate DESC
Limit 1;
SQL Fiddle

Before you try below code you must be reformat last visited date table structure like YYYY/MM/DD in SQL Table and you must replace actual tables name and columns name in below query.
SELECT MAX(table_b.last_visited_date) AS last_visited_date
FROM table_a
INNER JOIN table_b
ON table_a.state = table_b.state WHERE table_a.country = 'US' Limit 1;

Try this below script-
Note: As Tanmay said, you need to reformat your date values to get the correct output.
DEMO HERE
SELECT N.country,
N.mx_date LastVisitDate,
B.City,
B.State
FROM
(
SELECT Country,MAX(LastVisitDate) mx_date
FROM Table_A A
INNER JOIN Table_B B ON A.State = B.State
GROUP BY Country
)N
INNER JOIN Table_A A ON A.Country = N.Country
INNER JOIN Table_B B ON A.State = B.State
WHERE N.mx_date = B.LastVisitDate

SELECT top 1(country,
last_visit_date)
FROM A
JOIN B ON A.State = B.State
WHERE A.Country ="Country Name"
ORDER BY B.Last_visit_Date DESC

Related

How to have IN and NOT IN at same time

Can someone help me to figure out how is the best way to do this?
I have a list of people with cars. I need to execute a query that will return people that have a type of car and don't have another type at the same time.
Here is my example:
ID Name CarType
----------- ---------- ----------
1 John MINI VAN
1 John SUV
2 Mary SUV
2 Mary SEDAN
3 Paul SPORT
3 Paul TRUCK
4 Joe SUV
4 Joe MINI VAN
For instance, I want to display only people that have SUV AND DON'T have MINI VAN. If we try the clause CarType IN ('SUV') AND NOT IN ('MINI VAN'), this will not work, because the second statement is just ignored.
In order to return people that have a type but don't have another type at the same time, I tried the following:
Create a temporary table with the IN clause, let's say #Contains
Create a temporary table with the NOT IN clause, let's say #DoesNotContain
Join table with #Contains, this will do the IN clause
On the where clause, look for IDs that are not in #DoesNotContain table.
The query that I am using is this:
--This is the IN Clause
declare #Contains table(
ID int not null
)
--This is the NOT IN Clause
declare #DoesNotContains table(
ID int not null
)
--Select IN
insert into #Contains
SELECT ID from #temp where CarType = 'SUV'
--Select NOT IN
insert into #DoesNotContains
SELECT ID from #temp where CarType = 'MINI VAN'
SELECT
a.ID, Name
FROM
#temp a
INNER JOIN #Contains b on b.ID = a.ID
WHERE
a.ID NOT IN (SELECT ID FROM #DoesNotContains)
Group by
a.ID, Name
This will return Mary because she has a SUV but does not have a MINI VAN.
Here are my questions:
Is it possible to execute this IN and NOT IN in the query, without temp tables? Is there something new in SQL that does that? (Sorry, last time I worked with SQL was SQL 2005)
Should we use temp tables for this?
If this is the way to go, should I use IN and NOT IN instead of the JOIN?
How to replace the NOT IN clause with a JOIN?
Thank y'all!
EDIT
I just tested the solutions but unfortunately I did not specify that I need a combination of cartypes. My bad :(
For instance, if I want all users that have SUV and MINI VAN but not TRUCK AND NOT SEDAN. In this case it only John is returned.
This is normally accomplished with a single query in standard SQL, using NOT EXISTS:
SELECT *
FROM mytable AS t1
WHERE CarType = 'SUV' AND
NOT EXISTS (SELECT *
FROM mytable AS t2
WHERE t1.Name = t2.Name AND t2.CarType = 'MINI VAN')
The above query will select all people having CarType = 'SUV', but do not have CarType = 'MINI VAN'.
Here's one way
SELECT Id, Name
FROM Cars
WHERE CarType = 'SUV'
EXCEPT
SELECT Id, Name
FROM Cars
WHERE CarType = 'MINI VAN'
Or another
SELECT Id, Name
FROM Cars
WHERE CarType IN ('SUV', 'MINI VAN')
GROUP BY Id, Name
HAVING MIN(CarType) = 'SUV'
Or a more generic version that addresses the different requirement in the comment.
SELECT Id,
NAME
FROM Cars
WHERE CarType IN ( 'SUV', 'MINI VAN', 'TRUCK')
GROUP BY Id,
NAME
HAVING COUNT(DISTINCT CASE
WHEN CarType IN ( 'SUV', 'MINI VAN' ) THEN CarType
END) = 2
AND COUNT(DISTINCT CASE
WHEN CarType IN ( 'TRUCK' ) THEN CarType
END) = 0
Using LEFT JOIN:
SELECT a.ID,
Name
FROM #temp a
INNER JOIN #Contains b ON b.ID = a.ID
LEFT OUTER JOIN #DoesNotContains c ON c.ID = a.ID
WHERE c.ID IS NULL
The INNER JOIN will return records where b.ID and a.ID match.
The LEFT OUTER JOIN returns all records, with NULL where there is no match - adding WHERE c.ID IS NULL returns records from a that don't match to c.
The keyword except is your friend. This is the general idea
where carType in
(select carType
from cars
where you want to include them
except
select carType
from cars
where you want to exclude them)
You can work out the details.

In a left join, select row with value A, if not select row with value B

This must be simple, but I think I'm lost. I have a table A:
name id
Tom 1
Barbara 2
Gregory 3
...and table B:
id nickname preferred
1 Spiderman 0
1 Batman 1
2 Powerpuff 0
3 Donald Duck 0
3 Hulk 1
How do I query the table to get a nickname when it is preferred (1), or any other nickname if preferred is not available.
So the result for Tom would be "Batman", while the result for Barbara would be "Powerpuff".
Just an immediate solution:
select a.id,
b.nickname
from a
join b on a.id = b.id and b.prefered = 1
union all
select a.id,
b.nickname
from a
join b on a.id = b.id and b.prefered = 0
where a.id not in(
select a.id
from a
join b on a.id = b.id and b.prefered = 1
)
Fiddle http://sqlfiddle.com/#!7/0b7db/1
Try below Query:
Which 1. selects row with value A, otherwise, 2. select row with value B
using LEFT JOIN,
SELECT A.name, B.nickname
FROM A
LEFT JOIN
(
SELECT MAX(preferred) AS preferred, id
FROM B
GROUP BY id
)AS B1
ON A.id = B1.id
LEFT JOIN B ON B.preferred = B1.preferred AND B.id = B1.id
If SQLite supported analytic functions then that would provide a fairly clean and convenient solution. No such luck, though. It does simplify the problem that you want either all the preferred nicknames for a given person (of which there will be at most one) or all the non-preferred ones. It is then fairly straightforward to use an inline view to distinguish between those cases and apply a suitable filter:
SELECT p.name, pn.nickname
FROM
person p
JOIN (
SELECT id, MAX(preferred) AS preferred
FROM person_nickname
GROUP BY id
) flag
ON p.id = flag.id
JOIN person_nickname pn
ON pn.id = flag.id AND pn.preferred = flag.preferred

How to join 2 tables with alias and condition

Table1: Contractors
Contractor_No; -- PK
Contractor;
Table2: Contracts
Contract_No; -- PK
ProjDesc;
Contractor_No; -- FK
How to retrieve data by joining these 2 table with Contractor (from Table1), Contract_No, ProjDesc from (Table2)?
My SQL statment:
select a.Contractor, b.ProjDesc
from Contractors a, Contracts b
join Contractor a on a.Contractor_No = b.Contractor_No and b.Contract_No='1234';
You have some syntax errors:
SELECT a.Contractor
, b.ProjDesc
FROM Contractors a
JOIN Contracts b ON a.Contractor_No = b.Contractor_No
AND b.Contract_No = '1234'
select a.Contractor,
b.ProjDesc
from Constractors a
inner join contracts b on
a.contractor_no = b.contractor_no
where b.contract_no = '1234'

how use distinct in second join table in sql server

I have a SQL table consists of id, name, email,.... I have another SQL table that has id, email, emailstatus but these 2 id are different they are not related. The only thing that is common between these 2 tables are emails.
I would like to join these 2 tables bring all the info from table1 and if the email address from table 1 and table 2 are same and emailstatus is 'Bounced'. But the query that I am writing gives me more record than I expected because there are multiple rows in tbl_webhook(second table) for each row in Applicant(first table) .I want to know if applicant has EVER had an email bounce.
Query without join shows 23000 record but after join shows 42000 record that is because of duplicate how I can keep same 23000 record only add info from second table?
This is my query:
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK)
left outer join [tbl_Webhook] [H] (NOLOCK)
on A.Email = H.Email
and H.[event]='bounced'
this is sample of desired data:
id email name emailFromTable2 emailstatus
1 test2#yahoo.com lili test2#yahoo.com bounced
2 tesere#yahoo.com mike Null Null
3 tedfd2#yahoo.com nik tedfd2#yahoo.com bounced
4 tdfdft2#yahoo.com sam Null Null
5 tedft2#yahoo.com james tedft2#yahoo.com bounced
6 tedft2#yahoo.com San Null
Use a nested select for this type of query. I would write this as:
select id, application, load, firstname, lastname, email,
(case when BouncedEmail is not null then email end) as EmailFromTable2,
BouncedEmail
from (SELECT A.[Id], A.[Application], A.[Loan], A.[Firstname], A.[Lastname], A.[Email],
(case when exists (select 1
from tbl_WebHook h
where A.Email = H.Email and H.[event] = 'bounced'
)
then 'bounced
end) as BouncedEmail
FROM Applicant A (NOLOCK)
) a
You can also do this with cross apply, but because you only really need one column, a correlated subquery also works.
;WITH DistinctEmails
AS
(
SELECT * , rn = ROW_NUMBER() OVER (PARTITION BY [Email] ORDER BY [Email])
FROM [tbl_Webhook]
)
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK) left outer join DistinctEmails [H] (NOLOCK)
on A.Email = H.Email
WHERE H.rn = 1
and H.[event]='bounced'
i believe query below should be enough to select distinct bounced email for you, cheer :)
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK)
Inner join [tbl_Webhook] [H] (NOLOCK)
on A.Email = H.Email
and H.[EmailStatus]='bounced'
basically i just change the joining to inner join and change the 2nd table condition from event to emailstatus, if u can provide your table structure and sample data i believe i can help you up :)

sql - find max value

I have a table with 3 columns: Code, Year, percentage.
I need to return the code with the lowest (minimal) percentage in 2009. After this, I want also the name of the code, that exsist in other table that I made.
I only think using CREATE VIEW, but I prefer not to do so.
Select table.code, table.year, table.percentage, othertable.name
from table
inner join othertable on table.FKId = othertable.PKid
where year = 2009
and percentage =
(select min(percentage)
from table
where year = 2009)
Updated to include the othertable... since we don't have names.
UPDATED
Now that we have table names... Updated 3rd time now that I know year is string.
Select E.Code, C.Name
From dbo.Exam E
inner join dbo.Course C
ON E.Code = C.Code
Where E.Year = '2009' and --<-- PROBLEM LIKELY HERE year was string not int.
E.Fail = (select MIN(E2.Fail)
from dbo.Exam E2 where E2.Year = '2009') --<--Don't forget here too.
From comments: sample Data:
INSERT INTO Exam VALUES(333,'2009',40)
INSERT INTO Exam VALUES(333,'2009',20)
INSERT INTO Exam VALUES(555,'2009',19)
INSERT INTO Exam VALUES(444,'2009',19)
INSERT INTO Exam VALUES(777,'2009',23)
INSERT INTO Exam VALUES(333,'2009',0)
INSERT INTO Course VALUES(111,'Name1',5)
INSERT INTO Course VALUES(333,'Name2',5)
INSERT INTO Course VALUES(444,'Name3',6)
INSERT INTO Course VALUES(555,'Name4',3)
INSERT INTO Course VALUES(777,'Name5',3)
INSERT INTO Course VALUES(999,'Name6',6)
Assumption is result should be
Name2, 5
You can use a group by to find the lowest percentage for a year, and then join back to the main tables to find the corresponding other columns:
select *
from CodeYearPercTbl cyp
join CodeTbl c
on c.Code = cyp.Code
join (
select Year
, min(Percentage) as MinPerc
from CodeYearPercTbl
group by
Year
) as filter
on filter.Year = cyp.Year
and filter.MinPerc = cyp.Percentage
where cyp.Year = 2009
Table-1 : Code,Year,Percentage
Table-2 : Code,CodeName
select T1.Code,T2.CodeName,T1.Percentage from
(
select TOP 1 Code,Percentage
from Table-1
where Year = '2009'
order by Percentage asc
) T1 inner join Table-2 T2 on T1.Code = T2.Code
Try this:
select a.Code, c.Name
from YourTable a inner join AnotherTable c on a.Code = c.Code
where a.Percentage = (select MIN(Percentage)
from YourTable b where b.Year = '2009'
)