SELECT记录有2个主键

时间:2013-05-27 18:47:51

标签: sql-server-2008 primary-key

我有两张桌子:

Cust TABLE:

siteid nvarchar(2) PRIMARY KEY,
custid int PRIMARY KEY,
fname varchar(30),
lname varchar(30)

儿童表:

childid1 nvarchar(2) PRIMARY KEY,
childid2 int PRIMARY KEY,
siteid nvarchar(2),
custid int,
lname varchar(30),
lname varchar(30),
FOREIGN KEY(siteid)REFERENCES Cust(siteid),
FOREIGN KEY(custid)REFERENCES Cust(custid)

值:

卡斯特:

siteid | custid | fname | lname
A1     | 1111   | John  | S
A2     | 1111   | Steve | H
B1     | 2222   | Paul  | N
C3     | 3333   | Mary  | J

儿童:

childid1 | childid2 | siteid | custid | fname | lname
A6       | 1010     | A1     | 1111   | Lisa  | S
A8       | 1011     | A1     | 1111   | Linda | S
A9       | 1012     | A1     | 1111   | Jose  | S
D9       | 1013     | A2     | 1111   | Jake  | H
D1       | 1014     | B1     | 2222   | Judy  | N
D1       | 1015     | B1     | 2222   | Judy  | N

我正在寻找没有孩子的Cust,这是我的疑问:

SELECT * FROM Cust WHERE Cust.siteid NOT IN(
SELECT Children.siteid FROM Children
) AND Cust.custid NOT IN(
SELECT Children.custid FROM Children
)

但结果出来了。这里的正确查询是什么,因为表有复合主键?

2 个答案:

答案 0 :(得分:4)

表没有2个主键。有些人有复合主键,这似乎就是这种情况。如果Cust表格(siteid, custid)PRIMARY KEY

CREATE TABLE Cust
( siteid nvarchar(2),
  custid int,
  fname varchar(30),
  lname varchar(30),
  PRIMARY KEY (siteid, custid)              -- one primary key
) ;

那么你的外键定义是错误的。您应该有一个(复合)外键,引用(复合)主键:

CREATE TABLE Children
( childid1 nvarchar(2),
  childid2 int,
  siteid nvarchar(2),
  custid int,
  fname varchar(30),
  lname varchar(30),
  PRIMARY KEY (childid1, childid2),
  FOREIGN KEY (siteid, custid)               -- one foreign key 
    REFERENCES Cust(siteid, custid)
) ;

然后编写查询的一种方法是(更正:这是ANSI SQL,适用于其他DBMS但不适用于SQL-Server):

SELECT * 
FROM Cust 
WHERE (siteid, custid) NOT IN
      ( SELECT siteid, custid  
        FROM Children
      ) ;

或更好地使用NOT EXISTS因为它避免了可能使NULL版本显示未预期结果的NOT IN值的陷阱(其次是因为NOT IN不起作用)在SQL-Server中:)

SELECT * 
FROM Cust AS c
WHERE NOT EXISTS
      ( SELECT * 
        FROM Children AS ch
        WHERE ch.siteid = c.siteid
          AND ch.custid = c.custid
      ) ;

SQL-Fiddle

中进行测试

答案 1 :(得分:2)

表达查询的方法不止一种。在选择表之前,请查看指定聚簇和非聚簇主键,执行计划和ypercube关于表的注释的选项。 (我相信NOT IN不是可以理解的。)

select cust.siteid, cust.custid
from cust
left join children
       on cust.siteid = children.siteid
      and cust.custid = children.custid
where children.siteid is null;