Select Combination of columns from Table A not in Table B - sql

I have two sets of table with all the contacts on an Account their titles and etc. For data migration purposes I need to select All ContactsIds with their AccountID from Table A that do not exist in TableB. Its the combination of both the ContactId and the AccountID. I have tried the following:
Select * from Final_Combined_Result wfcr
WHERE NOT EXISTS (Select Contact_ID, Account_ID from Temp_WFCR)
I know this is completely off, but I have looked at a couple of other questions on here but was unable to find an appropriate solution.
I have also tried this:
Select * from Final_Combined_Result wfcr
WHERE NOT EXISTS
(Select Contact_ID, Account_ID from Temp_WFCR as tc
where tc.Account_ID=wfcr.Account_InternalID
AND tc.Account_ID=wfcr.Contact_InternalID)
This seems to be correct but I would like to make sure.

Select wfcr.ContactsId, wfcr.AccountID
from Final_Combined_Result wfcr
left join Temp_WFCR t_wfcr ON t_wfcr.ContactsIds = wfcr.ContactsId
AND t_wfcr.AccountID = wfcr.AccountID
WHERE t_wfcr.AccountID is null
See this great explanation of joins

#juergend's answer shows the left join.
Using a not exists you join in the subselect, it would look like this:
Select wfcr.*
from
Final_Combined_Result wfcr
WHERE NOT EXISTS
(Select 1 --select values dont matter here, only the join restricts.
from
Temp_WFCR t
where t.Contact_ID = wfcr.Contact_InternalID
and t.account_id = wfcr.Account_InternalID
)

Related

T-SQL : check if data exists in table

I am using a view that checks if data exists in another table and if it exists if shows the number of row's connected to that table. Now I was wondering if there might be a faster way of doing this, since I am only interested if there is data and not necessary how many data rows there are. I guess when it does not need to count it will be faster.
This is what I use now:
SELECT
dbo.user.id,
dbo.user.userCode,
COALESCE (TotalProducts.ProductsInback, 0) AS ProductsInback
FROM
dbo.user
LEFT OUTER JOIN
(SELECT COUNT(id_product) AS ProductsInback, userCode
FROM dbo.Product
GROUP BY userCode) AS TotalProducts ON dbo.Product.userCode = TotalProducts.userCode
WHERE
dbo.user.userCode = 'XYZ'
Now this works all fine an it gives me the number of products connected to the user XYZ that are in the back of the store. However I just want to know if the user has products in the back of the store, I don't need to know how many. That seems to me a faster solution (walking anyway to the back of the store). So replacing the COUNT with ... ?
You are right, for a lookup whether data exists in another table, we use EXISTS or IN, because we don't have to go through all matching rows then, but can stop at the first one found.
EXISTS:
SELECT
id,
userCode,
CASE WHEN EXISTS (SELECT * FROM dbo.Product p WHERE p.userCode = u.userCode )
THEN 1 ELSE 0 END AS ProductsInback
FROM dbo.user u
WHERE u.userCode = 'XYZ'
IN:
SELECT
id,
userCode,
CASE WHEN userCode IN (SELECT userCode FROM dbo.Product)
THEN 1 ELSE 0 END AS ProductsInback
FROM dbo.user
WHERE userCode = 'XYZ'
If you change your left join to an inner join, you will just get a list of users with products. The other users will not appear on the list.
SELECT
dbo.user.id,
dbo.user.userCode
FROM dbo.user
JOIN dbo.Product
ON dbo.Product.userCode= TotalProducts.userCode

How to select records which don't exist in another table or have a different status?

I am trying to select records from a temp table based on another temp table which holds their previous statuses (StatusHistory).
So if the record doesn't exist in the status table, then it should be selected. If the status of the record is different than the one in the StatusHistory table, then the record should be selected. Otherwise, if it exists with the same status in the StatusHistory table, then it should be ignored.
I have this SQL but it doesn't seem to be the best solution. Can you please point me to a better way to achieve that assuming that there are thousands of records in the tables? Would it be possible to achieve the same result with a JOIN statement?
SELECT AI.item
FROM #AllItems AI
WHERE NOT EXISTS (
SELECT * FROM #StatusHistory HS
WHERE HS.itemId = AI.itemId
) OR NOT AI.itemStatus IN ( SELECT HS.itemStatusHistory
FROM #StatusHistory HS
WHERE HS.itemId = AI.itemId
AND HS.itemId = AI.itemId )
Yes, you can do this with a LEFT JOIN.
SELECT AI.item
FROM #AllItems AI
LEFT JOIN #StatusHistory HS ON AI.itemId = HS.itemId
AND AI.itemStatus = HS.itemStatusHistory
WHERE HS.itemId IS NULL
A better solution, however, is to use NOT EXISTS:
SELECT AI.item
FROM #AllItems AI
WHERE NOT EXISTS
(
SELECT 1 FROM #StatusHistory SH
WHERE SH.itemId = AI.itemId
AND SH.itemStatusHistory = AI.itemStatus
);
As pointed out by Aaron, this usually performs better than a LEFT JOIN.

Opposite of UNION SQL Query

I have 2 tables :
interests (storing the interest ID and name)
person_interests(storing the person_id and interest_id)
How do I select all the interests that a particular person has not selected?
I have tried the following SQL Query and am still not getting the desired result
SELECT *
FROM interests LEFT JOIN person_interests
ON interests.id=person_interests.person_id
WHERE person_interests.id IS NULL
AND person_id=66;
Use NOT EXISTS
SELECT *
FROM interests
WHERE NOT EXISTS (
SELECT person_interests.interest_id
FROM person_interests
WHERE person_id = 66
AND interests.id = person_interests.interest_id
)
SELECT * from interests
WHERE interest_id NOT IN
(SELECT interest_id FROM person_interests WHERE person_id=66)
There are a couple things going on.
First, I think you have an error in your join. Shouldn't it be interests.id=person_interests.interest_id instead of interests.id=person_interests.person_id?
That aside, I still don't think you would be getting the desired result because your person_id filter is on the RIGHT side of your LEFT OUTER join, thus turning it back into an inner join. There are several ways to solve this. Here's what I would probably do:
SELECT *
FROM
(SELECT interests.*, person_id
FROM interests LEFT JOIN person_interests
ON interests.id=person_interests.interest_id
WHERE person_interests.id IS NULL )
WHERE person_id=66;

Is this a valid SQL query?

This is just an example, I'm doing something similar that is going to grab thousands of records.
SELECT * FROM
(SELECT * FROM zoodb) As TblA
INNER JOIN
(SELECT animal_ID, Max(checkup_year) AS latest_checkup FROM TblA GROUP BY animal_ID) as TblB
ON (TblA.animal_ID = TblB.animal_ID) AND (TblA.checkup_year = TblB.latest_checkup)
Basically in this, I want to grab the records only for the latest checkup year
Your query is not valid.
But you can do it this way:
SELECT * FROM zoodb z
INNER JOIN (SELECT animal_ID, Max(checkup_year) AS latest_checkup
FROM zoodb
GROUP BY animal_ID) aux ON aux.animal_ID = z.animal_ID AND aux.latest_checkup = z.checkup_year
SELECT * FROM
(SELECT * FROM zoodb) As TblA
....
There is no need for this sub query. The FROM in the outer query can handle it!
SELECT *
FROM zoodb AS TblA
...
The rest looks fine!
Edit:
As aF pointed out you cannot reference TblA from the inner join subquery (See aF's answer).
aF.'s answer is correct, but I thought I'd propose a solution that expresses your intention a little more clearly:
select *
from zoodb as TblA
where latest_checkup = (
select max(latest_checkup)
from zoodb
where animal_id = TblA.animal_id);
The lack of the [inner join (subselect)] also means that it won't get too messy if you need to add additional constraints in the future.
Also the query optimizer prefers inner joins to nested select statements, so you'll get a more optional execution plan

How to have a set of combination as a condition in SQL?

I'm working on an integration project and have created a batchlog table where I store which combinations have been exported already and then check new data against that batchlog table. It worked pretty well as long as I mostly just stored one ID in batchlog table, let's say Customer ID and then selected new rows from Customer table like this:
SELECT *
FROM Customer
WHERE CusId NOT IN (SELECT CusID FROM IntegrationBatchlog)
However, now the solution is more complex and same row from Customer table will be exported several times in combination with other data so now I have couple of separate stored procedures and more columns in IntegrationBatchlog table (CusID, OrdertypeID and PaymentMethod) and join clauses in my select so now it's more like.
SELECT * FROM Customer c
JOIN....
JOIN...
JOIN...
WHERE there is not a row with that CusID AND OrderTypeID AND PaymentMethod in batchlog table yet.
So here I should check whether or not this exact combination has already been exported but how do you do that when you have like three several ID columns in batchlog table and you want to exclude those rows where all the three ID's are already present in same row in batchlog table?
One way is to do a LEFT JOIN to the IntegrationBatchLog table and only insert rows that aren't present.
select *
from Customer c
LEFT OUTER JOIN IntegrationBatchLog i
on c.CusId = i.CusId
and c.OrderTypeID = i.OrderTypeID
and c.PaymentMethod = i.PaymentMethod
where
i.CusId is null
Use EXISTS, not IN. This allows multiple column matching
This is standard SQL
SELECT * FROM Customer c
JOIN....
JOIN...
JOIN...
WHERE NOT EXISTS (
SELECT * FROM IntegrationBatchlog I
WHERE C.CusID = I.CusID
AND C.OrderTypeID = I.OrderTypeID
AND C.PaymentMethod = I.PaymentMethod)
SELECT ...
FROM Customer c JOIN ...
WHERE NOT EXISTS (SELECT *
FROM IntegrationBatchLog I
WHERE I.CusID = c.CusId AND
I.OrderTypeId = c.OrderTypeID ...)
Maybe NOT EXISTS would work here. Here's an example from the MySQL docs (I don't know your DB) - http://dev.mysql.com/doc/refman/5.0/en/exists-and-not-exists-subqueries.html
The second example:
"What kind of store is present in no cities?"
SELECT DISTINCT store_type FROM stores
WHERE NOT EXISTS (SELECT * FROM cities_stores
WHERE cities_stores.store_type = stores.store_type);
Maybe yours could be:
SELECT * FROM Customer c
JOIN....
JOIN...
JOIN...
WHERE NOT EXISTS (
SELECT * FROM batchlog WHERE
c.CusID = batchlog.CusID AND
c.OrderTypeID = batchlog.OrderTypeID AND
c.PaymentMethod = batchlog.PaymentMethod
)