2011-01-09 39 views
2

我有以下兩個表SQL和運營工作不正常

LandParcels表

Blockid ParcelNo storPri 
======= ======== ======= 
52000105 3  State 
52000105 4  Private 
52000105 5  State 

操作表

Blockid ParcelNo ActionTaken 
======= ======== =========== 
52000105 3  Received 
52000105 3  Send to Computer 
52000105 4  Received 
52000105 5  Received 

我想找到的記錄Received但不Send to Computer

這是我的查詢

select 
    l.blockid, l.parcelno 
from 
    landparcels l 
left join 
    actions ac on l.blockid = ac.blockid and l.parcelno = ac.parcelno 
where 
    ac.actiontaken = 'Received' 
    and ac.actiontaken <> 'Send to Computer' 
    and ac.blockid = 52000105 

結果是

Blockid ParcelNo 
======= ======== 
52000105 3 
52000105 4 
52000105 5 

我想ParcelNo 4和5

+1

規範化的動作表,然後。 – Mchl 2011-01-09 08:34:12

+1

@Mchl,是什麼讓你說它沒有正常化? – Ronnis 2011-01-09 08:37:22

+0

你正在使用什麼數據庫**?該數據庫的哪個版本? – 2011-01-09 09:36:48

回答

0

請注意,在任何常用數據庫產品中,您都很難在AND運算符中發現一個簡單的錯誤。這裏的問題不是數據庫引擎沒有產生正確的結果,而是你不明白AND運算符的作用。

看看你的情況ac.actiontaken = 'Received' AND ac.actiontaken <> 'Send to Computer'。將要發生的事情是,引擎將檢查輸出中的每個可能的行,並確定它是否符合您指定的條件。那麼,對於第一行,actiontaken是否是'Received'?是。 actiontaken不是'Send to Computer'嗎?當然。所以這個行有資格。

事實上,任何一行的actiontaken「接收」將有資格,因爲根據定義,它也確實actiontaken 該行「發送到計算機」。

有很多方法可以得到你想要的答案。這裏是我的首選之一:

SELECT DISTINCT a.blockid, a.parcelno FROM actions a 
WHERE a.blockid = 52000105 AND a.actiontaken = 'Received' AND NOT EXISTS 
    (SELECT * FROM actions a2 WHERE a2.blockid = a.blockid AND 
            a2.parcelNo = a.parcelNo AND 
            a2.actiontaken = 'Send to Computer') 
0
select a.blockid 
     ,a.parcelno 
    from landparcels a 
    join actions  b on(a.blockid = b.blockid and a.parcelno = b.parcelno) 
where b.action_taken in('Received', 'Send to Computer') 
    and a.blockid = 52000105 
group 
    by a.blockid 
     ,a.parcelno 
having count(*) = 1 
    and min(b.action_taken) = 'Received'; 

或東西少花哨,可以找兩個1出的特殊情況外延伸:

select a.blockid 
     ,a.parcelno 
    from landparcels a 
    join actions  b on(a.blockid = b.blockid and a.parcelno = b.parcelno) 
where b.blockid = 52000105 
    and b.action_taken = 'Received' 
    and not exists(
     select 'x' 
     from actions x 
     where x.action_taken = 'Send to Computer' 
     and b.blockid = x.blockid 
     and b.parcelno = x.parcelno 
    ); 

我剛剛意識到你不需要joi ñ與landparcels,根據您的要求,但我保持原樣,以防您的真實需求需要該表中的數據。

更新 添加塊標識過濾

+0

您的第一個解決方案並不完全正確,因爲OP沒有聲明沒有第三個ActionTaken值,從而使得「有count(*)= 1」的子句不正確。 – kirakun 2011-01-09 08:54:44

1

如果你的數據庫支持tuplewhere條款,儘量響應

select * 
from landparcels 
where (blockid, parcelno) in 
(
    select blockid, parcelno 
    from actions 
    where actiontaken = 'Received' 
) 
and (blockid, parcelno) not in 
(
    select blockid, parcelno 
    from actions 
    where actiontaken = 'Send to Computer' 
) 

編輯marc_s:否則,試試這個版本,我認爲這是ANSI,而不是

select * 
from landparcels as p 
where exists 
(
    select 1 
    from actions 
    where actiontaken = 'Received' 
    and blockid = p.blockid 
    and parcelno = p.parcelno 
) 
and not exists 
(
    select 1 
    from actions 
    where actiontaken = 'Send to Computer' 
    and blockid = p.blockid 
    and parcelno = p.parcelno 
) 
0

你沒有說你所使用的數據庫系統 - 但SQL Server上,你可以使用此查詢的位置:

SELECT 
    lp.* 
FROM 
    dbo.LandParcels lp 
WHERE 
    EXISTS(SELECT * FROM abo.ActionTaken a 
      WHERE a.blockid = lp.blockid 
      AND a.parcelno = lp.parcelno 
      AND a.ActionTaken = 'Received') 
    AND NOT EXISTS(SELECT * FROM dbo.ActionTaken a 
        WHERE a.blockid = lp.blockid 
        AND a.parcelno = lp.parcelno 
        AND a.ActionTaken = 'Send to Computer') 

這導致了這個輸出這裏:

blockid parcelno storePrio 
52000105  4   Private 
52000105  5   State 
0
SELECT Blockid, PacelNo FROM LandParcels 
WHERE (ParcelNo IN (SELECT ParcelNo FROM Actions WHERE ActionTaken = 'Received') 
AND (ParcelNo NOT IN (SELECT ParcelNo FROM Actions WHERE ActionTaken = 'Send to Computer'))) 
0

上@ Kirakun的「行建設者的回答進一步的變化,依然是ISO/ANSI語法,但是這是在SQL Server確實支持:

SELECT blockid, parcelno 
    FROM landparcels 
INTERSECT 
SELECT blockid, parcelno 
    FROM actions 
WHERE actiontaken = 'Received' 
EXCEPT 
SELECT blockid, parcelno 
    FROM actions 
WHERE actiontaken = 'Send to Computer';