how use distinct in second join table in sql server - sql

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 :)

Related

SQL Get records with max value for each group

I have 2 tables Journal and Users
Journal looks like this:
TransTime
RegNumber
UserID
5/26/2022 11:00:00
101
3
5/26/2022 11:30:00
102
2
5/26/2022 13:00:00
101
5
5/26/2022 14:30:00
103
4
5/26/2022 15:00:00
102
1
Users table
UserID
Name
1
Ross
2
Rachel
3
Chandler
4
Monica
5
Joey
What I would like to do is get a table of the Registers and their most recent user names. This should seem very simple. But since I am joining tables on the userID, I am getting all 5 records on the first table. But it should look like this:
RegNumber
LastUser
101
Joey
102
Ross
103
Monica
I have tried a variety of solutions but haven't found the right one. Any help is appreciated.
You can use a temptable or cte structure to rank your data based on RegNo and Trantime like below, then retrieve the most updated users for each journal:
CREATE TABLE #Journals (TranTime DATETIME, RegNo INT, UserId INT)
CREATE TABLE #Users (UserId INT, UserName NVARCHAR(100))
INSERT INTO #Users VALUES(1,'Ross'),(2,'Rachel'),(3,'Chandler'),(4,'Monica'),(5,'Joey')
INSERT INTO #Journals VALUES ('5/26/2022 11:00:00',101,3),('5/26/2022 11:30:00',102,2),
('5/26/2022 13:00:00',101,5),('5/26/2022 14:00:00',103,4),('5/26/2022 15:00:00',102,1)
;WITH cte as (
SELECT *,rn=ROW_NUMBER() OVER (PARTITION BY RegNo ORDER BY TranTime DESC)
FROM #Journals
)
SELECT RegNo, u.UserName
FROM cte
INNER JOIN #Users u ON u.UserId = cte.UserId
WHERE rn=1 --since sort by TranTime is descending, it'll give you the latest user for each specific RegNo
ORDER BY RegNo
Tested and it works on SQL Server 2016.
if you start with an inner join of the max transtime per regNumber, then join with user table:
Select J.RegNumber, U.Name
From Journal J
Inner join
(Select Max(TransTime) as TransTime, RegNumber
From Journal
Group by RegNumber) J2 on J.TransTime = J2.TransTime and J.RegNumber = J2.RegNumber
Inner join
Users U on J.UserID = U.UserID
Here is an option using a CTE:
;with cte as
(
Select RegNumber,
UserID = max(UserID)
From journal
group by RegNumber
)
Select RegNumber = C.RegNumber,
LastUser = U.Name
From cte C
Join users U ON U.Userid = C.UserID
order by C.RegNumber
This answer is not, at its core, substantively different from the others. However, in terms of being helpful to the target audience it's more readable, more self-documenting, and more standard in terms of formatting.
Sidebar: This SQL takes the data design at face value, as a given, with the implicit assumption that TransTime is the PK or at least uniquely indexed, possibly in conjunction with RegNumber. Bottom line, it would be good to have a little more info about the key structure along with the original question.
WITH LatestEntries AS
(
SELECT
MAX(TransTime) AS LatestTimeForReg
,RegNumber
FROM
Journal
GROUP BY
RegNumber
)
SELECT
J.RegNumber
,U.[Name] AS LastUser
FROM
LatestEntries LE
INNER JOIN Journal J ON LE.LatestTimeForReg = J.TransTime AND LE.RegNumber = J.RegNumber
INNER JOIN Users U ON J.UserID = U.UserID
ORDER BY
J.RegNumber
;
select u.Name, j.*
from journal j
inner join (
select max(TransTime) last_update, RegNumber
from journal
group by RegNumber
) t1
inner join j.RegNumber = t1.RegNumber
and t1.last_update = j.TransTime
left join Users_Journal uj on j.UserID= uj.UserID

Select Count take too long to be executed

I'm executing two queries. One that return the number of records and one that display the results. But how come the query that return the total of records takes 11 sec to be excecuted while the one displaying the result take less than 1 sec to be executed ? It should be the opposite, no ?
SQL that return the total of records is executed after 11 sec
(SELECT count(*) as id
FROM (
SELECT DISTINCT title, version
FROM book AS b
WHERE b.title IS NOT NULL AND NOT EXISTS (SELECT * FROM user AS u WHERE u.column1 = b.column1)
UNION ALL
SELECT DISTINCT title, version
FROM book2 AS b2
WHERE b.title IS NOT NULL AND EXISTS (SELECT * FROM user AS u WHERE u.column2 = b.column1)
) c )
SQL that display the result is executed in less than 1 sec
SELECT DISTINCT title, version
FROM book AS b
WHERE b.title IS NOT NULL AND NOT EXISTS (SELECT * FROM user AS u WHERE u.column1 = b.column1)
UNION ALL
SELECT DISTINCT title, version
FROM book2 AS b2
WHERE b.title IS NOT NULL AND EXISTS (SELECT * FROM user AS u WHERE u.column2 = b.column1)
You could try this:
SELECT COUNT(1)
FROM
(
SELECT DISTINCT title, version
FROM book b
LEFT JOIN u ON b.column1 = u.column2
LEFT JOIN u2 ON b.column1 = u2.column1
WHERE u2.column1 IS NULL
AND b.title IS NOT NULL
) sub
There are chances that you can improve your query here is one of the example and you can check other as well shared by friends
SELECT COUNT(1)
FROM book AS b
LEFT OUTER JOIN User U ON u.Column1 = b.column1
LEFT OUTER JOIN user u1 ON u1.Column2 = b.column1
WHERE b.title IS NOT NULL
AND u.Id IS NULL -- with assumption u might have another column id
AND u1.Id IS NULL -- with assumption u1 might have aother column or
GROUP BY title,Version
You are comparing apples and oranges. The count(*) version has to process all the data before it can return anything.
The more detailed version can start returning rows as they become available -- which is presumably when the first subquery starts returning rows.
I don't think either of these queries are what you really need, but this question does not provide that information.
Also, are book and version not unique? I wonder if this does what you want:
SELECT COUNT(*)
FROM book b
WHERE b.title IS NOT NULL AND
( NOT EXISTS (SELECT 1 FROM user u WHERE u.column1 = b.column1) OR
EXISTS (SELECT 1 FROM user u WHERE u.column2 = b.column1)
);
You can also use COUNT(DISTINCT):
SELECT COUNT(DISTINCT b.title + ':' + b.version)
. . .
(SELECT **count(title)** as id
FROM (
SELECT DISTINCT title, version
FROM book AS b
WHERE b.title IS NOT NULL AND NOT EXISTS (SELECT * FROM user AS u WHERE u.column1 = b.column1)
UNION ALL
SELECT DISTINCT title, version
FROM book2 AS b2
WHERE b.title IS NOT NULL AND EXISTS (SELECT * FROM user AS u WHERE u.column2 = b.column1)
) c )
"*" is never advisable as it accounts for all unnecessary details too.

SQL Multiple Joins Query

Here I have two tables committee_colleges and colleges.
Structure of tables is something like this
committee_colleges
committeeCollegeId collegeId committeeMemberId
1 2 1
2 2 2
3 3 2
I am storing committeeMemberId from committeeMember table.And one college can have multiple committee Members.How can I wite a query to display only the colleges assigned to specific committee Member.
For Example,if committeeMember by id=2 has logged in I want to display colleges by id=2,3.
In college table I have like this,
collegeId typeName
1 AICTE
2 NCTE
3 NTCS
This is Committee Member table
committeeMemberId name
1 xyz
2 abc
Now I am writing something like this,but i know its wrong because I dont know how to take it from College table since I am displaying College details.
SELECT cc.committeeCollegeId as committeeCollegeId,
c.collegeId as collegeId,
cc.committeeMemberId as committeeMemberId
FROM committee_college as cc
left outer join College as c
on cc.collegeId = c.collegeId
where cc.committeeMemberId=:committeeMemberId
order by cc.committeeCollegeId asc
Can anyone tell how to display colleges based on its assignment to particular committeeMember?
You were close, you need INNER JOIN instead of LEFT JOIN:
SELECT DISTINCT C.typeName --<<== put here all the columns that you want in output
FROM committee_colleges CC
INNER JOIN college C
ON C.collegeId = CC.collegeId
WHERE CC.committeeMemberId = 2 --<<== your input parameter
EDIT: added DISTINCT
Hope it helps.
You can use below sql statement for the same
DECLARE #committeeMemberId INT = 2 -- Id of Committee member
;WITH CTE_MemberCommittee AS
(
SELECT CollegeId
FROM committee_colleges
WHERE committeeMemberId = #committeeMemberId
)
SELECT collegeId, typeName
FROM college
WHERE collegeId IN (SELECT CollegeId FROM CTE_MemberCommittee)
You can use simple inner join for that,
If you want collegename based on memberId use following query,
select a.collegeid,a.typeName from
college a, committee_colleges b, committe_member c
where a.collegeid = b.collegeid and
b.committeememberid = c.committeeMemberId
and c.committeeMemberId = '2'
If you want collegename based on committemember name then use following query,
select a.collegeid,a.typeName from
college a, committee_colleges b, committe_member c
where a.collegeid = b.collegeid and
b.committeememberid = c.committeeMemberId
and c.Name = 'xyz'
Hope it will help.
try this:
DECLARE #LoginCommitteeMemberId INT=2
SELECT t2.Name AS MemberName,
t3.TypeName AS CollageName
FROM committee_college t1
INNER JOIN Committee_Member t2
ON t1.committeeMemberId = t2.committeeMemberId
INNER JOIN College as t3
ON t1.collegeId = t3.collegeId
WHERE t1.committeeMemberId = #LoginCommitteeMemberId

Alias table that's actually a pivoted one?

I have this query:
SELECT
A.USERID
A.NAME
PVT.PHONE 'PROBABLY A CASE STATEMENT ON NULL WILL GO HERE...
PVT.ADDRESS 'ON HERE AS WELL...
FROM
USERS A
'I NEED TO CREATE A PIVOT TABLE HERE WITH THE ALIAS OF 'PVT' ON TABLE 'B'
B Contents:
UserID PHONE ADDRESS TYPE
1 444-555-2222 XXXXXXX PHONE
1 XXXXXXX 66 Nowhere NOTADDRESS
I want, on the same row, the user's phone by getting B.PHONE if TYPE = 'PHONE'.
I also want, on the same row, the user's address by getting B.ADDRESS content if TYPE = 'ADDRESS'.
As you see in the table dump above, I don't have a record matching the user ID AND TYPE = 'ADDRESS'
So I would need to show a blank or 'No address' in the main SELECT which will show the phone, but on the same row, blank or 'No address'.
I don't want to create an INNER JOIN because if there are no matching UserID's in B, the query will not return the info that I have in table A for that user.
Also, a LEFT JOIN will create two rows, which I don't want.
I think I pivoted table as alias would do it, but I don't know how to create such an alias.
Any ideas ?
How about using conditional aggregation?
SELECT A.USERID, A.NAME
B.PHONE, B.ADDRESS
FROM USERS A LEFT JOIN
(SELECT UserId, MAX(CASE WHEN TYPE = 'PHONE' THEN PHONE END) as PHONE,
MAX(CASE WHEN TYPE = 'ADDRESS' THEN ADDRESS END) as ADDRESS
FROM B
GROUP BY UserId
) B
ON B.UserId = A.UserId;
If you have to use PIVOT then you'd need the pivot in a subquery and left join to it
SELECT
A.USERID,
A.NAME,
PVT.PHONE,
PVT.[ADDRESS]
FROM
Users A
LEFT JOIN (SELECT *
FROM
(SELECT
UserID,
[Type],
(CASE [Type] WHEN 'PHONE' THEN PHONE WHEN 'ADDRESS' THEN [Address] END) Info
FROM UserInfo) AS UI
PIVOT (
MAX(Info)
FOR [Type] IN ([PHONE], [ADDRESS])
) P
) PVT ON A.UserID = PVT.UserID
This gives you pretty much the same execution plan as the conditional aggregation query, but not as easy on the eyes.
SQL Fiddle

Oracle Statement does not count correctly

I've got a SQL-statement with a - for me not explainable - strange behaviour.
Perhaps you could find what's wrong:
When I use the statement
select count(*) from department
I got 2755 results
Using the following statement
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.buildingid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.buildingid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
I got 2755 results too.
But when I want to combine the two statements with a left join:
select count(*) from department
left join
(
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.buildingid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.buildingid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
) postadress
on
department.buildingid = postadress.buildingid;
I got 3648513 results.
My expectation was, that I get only 2755 results.
Where's the mistake?
Thanks for help!
I assume that buildingid is not unique (for my reasoning to hold true, it can't be unique)
Imagine following simple tables
TableA
create TableA (name VARCHAR(32));
insert into TableA values ('Lieven');
insert into TableA values ('Lieven');
TableB
create TableB (name VARCHAR(32));
insert into TableB values ('Lieven');
insert into TableB values ('Lieven');
insert into TableB values ('AnyOtherValue');
Select statement
select * from TableA a left outer join TableB b on a.name = b.name
As each record of TableA is matched with each record of TableB where the name is equal, this will result in 4 records (the AnyOtherValue is dissmissed as it doesn't match)
The first record of TableA is returned with two of three records of `TableB'
The second record of TableA is returned with two of three records of `TableB'
The query
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.buildingid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.buildingid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
will return one row per department that has usepostaladresssupporter as either 0 or 1 (note that records with other values will not be included, this may or may not be a problem depending on the constrainst of this column).
The unique key of this query results is probably something like departmentid (you will need to include that column in your select criteria).
So the correct query should look something like this:
select * from department
left join
(
select
building1.street, building1.streetno, building1.plz, building1.city, dept1.departmentid
from
department dept1
left join
supporter sup
on
dept.supporterid = sup.id
left join
building building1
on
sup.buildingid = building1.ibuildingid
where
dept.usepostaladresssupporter = 1
union all
select
building2.street, building2.streetno, building2.plz, building2.city, dept2.departmentid
from
building building2
right join
tueks_department dept2
on
dept2.buildingid = building2.ibuildingid
where
dept2.usepostaladresssupporter = 0
) postadress
on
department.departmentid = postadress.departmentid;
Your query will go wrong on data something like this:
Departmentid BuildingId Name
1 1 Dept1
2 2 Dept2
3 2 Dept3
The multiplying effect is not quite equal to deptcount * deptcount, but rather it is buildingcount * buildingcount + deptcount - buildingcount