2012-10-14 40 views
0

選擇A取決於一些外地表B中

TableA (TableAId int PK, Name varchar) 
TableB (OtherId, TableAId FK, TimeBegin timestamp ,TimeEnd timestamp) 

我想從TableA的姓名(或名稱),其中有TimeEnd = NULL TableB中選擇。

嘗試過這樣的事情:

SELECT  TableAId, Name 
FROM  TableA 
WHERE  
(
TableAId NOT IN 
       (
       SELECT TableAId FROM TableB WHERE TimeEnd is null 
       ) 
); 

它工作正常,當我有一些記錄具有空TimeEnd有的還帶有不爲空TimeEnd,但它不工作時,我有沒有TimeEnd集中沒有記錄。

如何解決?

+1

timestamp實際上並不是一個時間相關的數據類型。你的意思是DATETIME嗎? –

回答

1

您問題有兩種可能的答案:

IF OBJECT_ID('dbo.TableB') IS NOT NULL 
    DROP TABLE dbo.TableB; 
IF OBJECT_ID('dbo.TableA') IS NOT NULL 
    DROP TABLE dbo.TableA; 

CREATE TABLE dbo.TableA 
    (
    TableAId INT PRIMARY KEY, 
    Name VARCHAR(100) 
); 
CREATE TABLE dbo.TableB 
    (
    OtherId INT PRIMARY KEY, 
    TableAId INT FOREIGN KEY REFERENCES TableA (TableAId), 
    TimeBegin DATETIME, 
    TimeEnd DATETIME 
); 


INSERT INTO dbo.TableA 
     (TableAId, Name) 
VALUES (1, 'aaa'), 
     (2, 'bbb'), 
     (3, 'ccc'), 
     (4, 'ddd'); 

INSERT INTO dbo.TableB 
     (OtherId, TableAId, TimeBegin, TimeEnd) 
VALUES (1, 1, GETDATE(), NULL), 
     (2, 2, GETDATE(), GETDATE()), 
     (3, 2, GETDATE(), NULL), 
     (4, 3, GETDATE(), GETDATE()); 


SELECT A.* 
FROM dbo.TableA A 
WHERE EXISTS (SELECT 1 
       FROM dbo.TableB B 
       WHERE A.TableAId = B.TableAId 
         AND B.TimeEnd IS NULL); 

SELECT A.* 
FROM dbo.TableA A 
WHERE EXISTS (SELECT 1 
       FROM dbo.TableB B 
       WHERE A.TableAId = B.TableAId 
         AND B.TimeEnd IS NULL) 
     AND NOT EXISTS (SELECT 1 
         FROM dbo.TableB B 
         WHERE A.TableAId = B.TableAId 
           AND B.TimeEnd IS NOT NULL); 

第一個select從TableA返回TableB中至少有一個匹配記錄存在且TimeEnd爲NULL的所有記錄。

第二個select從TableA中返回記錄,TableB中的所有匹配記錄fullfil TimeEnd IS NULL。

第二個選擇可以改寫爲

SELECT A.* 
FROM dbo.TableA A 
LEFT JOIN (SELECT TableAId, 
        MIN(CASE WHEN TimeEnd IS NULL THEN 1 
          ELSE 0 
         END) AllAreNull 
      FROM dbo.TableB 
      GROUP BY TableAId 
     ) AS B 
     ON A.TableAId = B.TableAId 
WHERE B.AllAreNull = 1; 

這是有點不太容易理解,但在大多數情況下更快顯著執行。但是你應該運行你自己的性能測試來確保。

如果TableA中的每條記錄在TableB中最多有一條記錄,那麼您可以使用第一條select語句。

最後,您的代碼與描述文本不匹配。如果您實際上正在查找具有endtime值的記錄,則需要在所有上面的select語句中將IS NULL替換爲IS NOT NULL,反之亦然。

+0

我不相信它必須如此複雜。我也在考慮一些子選擇(用左連接選擇,然後過濾它),但是基於子查詢的最後一個查詢是完美的。謝謝。 – Kamil

0

我想你可能需要先加入2代表如下面的例子演示:

SELECT  TableA.TableAId, TableA.Name 
FROM  TableA 
INNER JOIN TableB 
ON TableA.TableAId = TableB.TableAId 
WHERE  
(
TableA.TableAId NOT IN 
       (
       SELECT TableAId FROM TableB WHERE TimeEnd is null 
       ) 
); 
+0

這也可能導致記錄重複。 –

+0

內部連接將不會選擇TableB中不存在的Id。 – Kamil

1

試試這個

Select * from TableA a 
Left Join TableB b ON a.TableAId = b.TableAId 
WHERE b.TimeEnd IS NULL 

中的not null基於

Select * from TableA a 
Left Join TableB b ON a.TableAId = b.TableAId 
WHERE b.TimeEnd IS NOT NULL 
+0

這可能會導致記錄被複制,如果表b中的特定行有多個子表b中的一個子 –

+0

我需要那裏沒有空值的記錄。 – Kamil

+0

嘗試內連接而不是左連接。 –

相關問題