views:

93

answers:

4

I have 3 tables

1) tblPurchaser having 2 columns:

PurchaserId   PurchaserName
1             A1
2             A2
3             A3

2) tblCar having 2 columns:

CarId   Carname
11      C1
12      C2
13      C3
14      C4

And the last is a junction table tblInformation where the information about those persons are given who has purchased cars.

PurchaserId  CarId
1            11
1            12
2            11
2            13

Now I need to write a set based query where I can be able to obtain the information of those cars which has not been purchased by the persons

Desired Output

PurchaserId  CarId
1            13
1            14
2            12
2            14      
3            11
3            12
3            13
3            14

Note: This is a real time problem which I am implementing in my project. Because of privacy of company, I have changed the tables and information. But my situation is something similar Please help me

Edited

So far I have written this query:

SELECT 1 as purchaserid,carid from tblcar
where carid not in (select carid from tblinformation where purchaserid = 1)
union all
SELECT 2 as purchaserid,carid from tblcar 
where carid not in (select carid from tblinformation where purchaserid = 2)
union all
SELECT 3 as purchaserid,carid from tblcar 
where carid not in (select carid from tblinformation where purchaserid = 3)

But as you can make out that i am hardcoding the purchaserid's. And also in real time I will not know how many id's will be there. So everything has to be done at runtime.

Please helpenter code here

+2  A: 

Clue: NOT EXISTS

You should really try to do some homework yourself... 3rd question today...

gbn
Sir, I have edited the question by stating the query which i have written. Pls help now
priyanka.sarkar
+1  A: 

Try this:

SELECT PurchaserID, CarID
FROM Purchasers
CROSS JOIN Cars
    EXCEPT
SELECT *
FROM tblInformation


Here is a SQL script that demonstrates that this technique works correctly:

declare @soPurchaser table(PurchaserId int,  PurchaserName varchar(4));
insert @soPurchaser select 1,'A1'
insert @soPurchaser select 2,'A2'
insert @soPurchaser select 3,'A3'

Declare @SOtblCar table(CarId int, Carname varchar(4))
insert @SOtblCar select 11,'C1'
insert @SOtblCar select 12,'C2'
insert @SOtblCar select 13,'C3'
insert @SOtblCar select 14,'C4'

Declare @SOtblInfo table(PurchaserId int, CarId int)
insert @SOtblInfo select 1,11
insert @SOtblInfo select 1,12
insert @SOtblInfo select 2,11
insert @SOtblInfo select 2,13

SELECT PurchaserID, CarID
FROM @soPurchaser
CROSS JOIN @SOtblCar
    EXCEPT
SELECT *
FROM @SOtblInfo


The SQL Set operators (UNION, INTERSECT, and EXCEPT) all operate on two table-sets. You will note that they have no way to map the columns from one set to the other. In all cases in SQL when column must be mapped to each other, but there is no syntax to do it explicitly, then they are always mapped based on column order.

So in this one case, if you have one of the table's column order wrong, then it will not work correctly.

RBarryYoung
But it not working. I am getting all the recordsPurchaserID CarID1 111 121 131 142 112 122 132 143 113 123 133 14
priyanka.sarkar
There there is something wrong either with the data in your DB or with what you have told us. Please see my additional script (above) that demonstrates the correctness of my approach.
RBarryYoung
I am sorry, you solution is right. I am strange to find out that, in the tblInformation, the columns were defined as CarId,PurchaserId whereas in the post I have defined as PurchaserId,CarId. When I ran the script which you have provided, I was getting all the records. but when I changed the order of display as SELECT CarId,PurchaserId I am getting the correct result. Could you please tell me why this happened?Both are foreign key in the tblInformation. It is just the order that caused the problem. I really don't know the cause of such behaviour. Can you please help me to grasp the logic
priyanka.sarkar
addl note added to explain this.
RBarryYoung
Thanks for your explanation.
priyanka.sarkar
+2  A: 

LEFT JOIN ... WHERE ... IS NULL to the rescue:

SELECT tblPurchaser.PurchaserId, tblCar.CarId 
  FROM tblPurchaser JOIN tblCar 
  LEFT JOIN tblInformation ON(
    tblPurchaser.PurchaserId = tblInformation.PurchaserId 
    AND tblCar.CarId = tblInformation.CarId) 
  WHERE tblInformation.CarId IS NULL
Alex Martelli
It is throwing errorMsg 4104, Level 16, State 1, Line 8The multi-part identifier "tblPurchaser.PurchaserId" could not be bound.
priyanka.sarkar
@pewned_123, I see you spelled your ids in lowercase in part of your question (the queries), but you uppercased them elsewhere (the sample tables you give!), so if your DB engine is case-sensitive your question is deeply flawed and you need to fix it. Also I use the same case as the answer you chose to accept, so I don't see how that query could run while mine doesn't...?!
Alex Martelli
Hi Alex, I found the problem. Insetead of Join, it should be CROSS JOIN and your quesry is working great. I think it may be of slip of finger. Thank you again.Instead of FROM tblPurchaser JOIN tblCar I used FROM tblPurchaser CROSS JOIN tblCar
priyanka.sarkar
+1  A: 

Try this

 select pur.PurchaserId, car.CarId
   from tblPurchaser pur, tblCar car
  where not exists (select 1 from tblInformation  where PurchaserId = pur. PurchaserId and CarId = car. CarId) 
 order by pur.PurchaserId;
Alexey Sviridov
"ORDER BY 1": seriously?
gbn
@gbnOf course... Anything wrong?
Alexey Sviridov
Sir, I modifed your code and this also works great. Why EXCEPT operator didnot came in my mind firstselect PurchaserId,CarId from tblPurchaser , tblCar EXCEPTSELECT *FROM tblInformation
priyanka.sarkar
I need to know for my sake of understanding why you have used select 1 from tblInformation? Please answer
priyanka.sarkar
Hm... except is more elengant, i'm agree, but less portable to other SQL dialects. exists work at most modern engines today, and it's an 'old scool' :)'select 1', just because we don't need any field values in our not exists subselect, so using simple constant is a bit efficient then 'select *' for example. But this optimisation needed only if you write selects about 70-80 lines (there is in my projects).select count(*) and select count(0) - same case.
Alexey Sviridov
@Alexey: http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/06/bad-habits-to-kick-order-by-ordinal.aspx
gbn
@gbn: Of course know about this issues, used here just for quick answer
Alexey Sviridov
@Alexey: fair enough, but people might assume it's *OK* because they saw it on SO
gbn
@gbn: People must know it theyself :) but thnx anyway, edited.
Alexey Sviridov