2017-03-15 83 views
0

我有兩個MySQL表:SQL計數有不匹配的記錄在一個一對多的關係

調查(日期,地點,公里) 主鍵:時間+地點 (每調查一個記錄)

標本(日期,地點,種類)(零所或多個記錄的每調查日期和地點)

我想找到調查的數量和受訪公里的總和,其中標本表包含任何記錄特定物種。換句話說,沒有找到特定物種的調查數量。

調查的總數爲:

​​

發現在沒有標本發現調查的數量很簡單:

select count(s.date) as surveys, sum(s.kilometers) as KM_surveyed 
from surveys=s left join specimens=p 
on (s.date=p.date and s.location=p.location) 
where p.date is null; 

+---------+-------------+ 
| surveys | KM_surveyed | 
+---------+-------------+ 
| 8820 | 15848.26 | 
+---------+-------------+ 

的標本中記錄的總數爲:

select count(*) from specimens; 

+-----------+ 
| count(*) | 
+-----------+ 
|  51566 | 
+-----------+ 

上的所有調查,結果發現斑海豹(HASE)的正確號碼是:

select count(*) from specimens where species = 'HASE'; 

+-----------+ 
| count(*) | 
+-----------+ 
|  662 | 
+-----------+ 

找到發現Harbor Seals(HASE)的調查數量並不容易。在沒有斑海豹(HASE)被發現發現調查的數量

select count(s.date), sum(s.kilometers) 
from surveys=s 
left join specimens=p on (s.date=p.date and s.location=p.location) 
where p.species = 'HASE'; 

+---------+-------------+ 
| surveys | KM_surveyed | 
+---------+-------------+ 
|  662 |  2030.70 | WRONG! that is number of specimens not surveys 
+---------+-------------+ 


由於標本表通常包含每調查多條記錄,該查詢返回不調查的數量卻發現HASE的樣本數目也不容易。該查詢返回不調查的電話號碼,但是沒有斑海豹發現的標本數量:

select count(s.date), sum(s.kilometers) 
from surveys=s 
left join specimens=p on (s.date=p.date and s.location=p.location) 
where p.species <> 'HASE' or p.date is null;` 

+---------+-------------+ 
| surveys | KM_surveyed | 
+---------+-------------+ 
| 50904 | 151310.49 | 
+---------+-------------+ 

錯了! 50904 =非HASE數標本

如何構造查詢到正確計算,其中斑海豹被發現調查的數量和調查計數時,並沒有發現他們?

+0

我想可能會丟失不同的信息 –

+0

如果您將一個不同的主鍵用於調查以及日期+位置組合以外的其他樣本,那麼這樣做會容易得多,因爲您想查找Harbor Seals所在的調查數量找到/未找到。由於您的樣本表也使用日期+位置,因此您必須決定是否是特定的日期或時間,您將考慮「位置」。這導致更復雜的問題/查詢超出必要。 –

+1

這是什麼:'從調查= s左加入標本= p'?你不能在表名和別名之間加'='。 – Barmar

回答

1

您可以使用WHERE子句中的EXISTS/NOT EXISTS子查詢。

調查其中HASEspecimens表中找到:

select count(*), sum(s.kilometers) 
from surveys s 
where exists (
    select * 
    from specimens p 
    where s.date=p.date 
     and s.location=p.location 
     and p.species = 'HASE' 
) 

調查其中HASE未在specimens表中找到:

select count(*), sum(s.kilometers) 
from surveys s 
where not exists (
    select * 
    from specimens p 
    where s.date=p.date 
     and s.location=p.location 
     and p.species = 'HASE' 
) 

到所述第一查詢的另一種可能是:

select count(*), sum(s.kilometers) 
from (
    select distinct date, location 
    from specimens 
    where species = 'HASE' 
) p 
join surveys s using (date, location) 

根據數據(如果'HASE'是一種罕見的「物種」),它可能會更快。

Barmar已經發布了第二個查詢的最佳替代方案。

1

當您在執行LEFT JOIN來查找不匹配的行時,應該將不應匹配的條件放入ON子句中,而不是WHERE子句。

SELECT COUNT(*), SUM(s.kilometers) 
FROM surveys AS s 
LEFT JOIN specimens AS p ON s.date = p.date and s.location = p.location 
    AND p.species = 'HASE' 
WHERE p.date IS NULL 
+0

這也是我對「未找到」查詢的選擇。 –

0

爲什麼人們很難找到連接?

發現其中斑海豹(HASE)被發現調查數量:尋找在沒有斑海豹(HASE),未發現調查的數量

select count(distinct concat(s.location, s.date)) 
from surveys s 
Inner join specimens p 
on (s.date=p.date and s.location=p.location) 
where p.species = 'HASE'; 

僅僅是調查的數量之差(你已經擁有)和上面的值。由於這兩個查詢返回一行查詢的笛卡爾積會給在一個單一的輸出中列的值,而只是有那麼一點不同:

Select count(*), sum(kilometres) 
From (
    Select kilometres 
    From surveys s 
    Left join specimens p 
    on (s.date=p.date and s.location=p.location) 
    and p.species = 'HASE' 
    Where p.species is null 
) As zero_surveys; 

(還有其他幾種方法來寫上面的查詢)

+0

「內部連​​接」不起作用。問題在於每個樣本記錄都與調查記錄相符,並且許多調查有多個樣本,因此同一個調查會被多次計數。帶有內部連接的查詢獲得與具有左連接的查詢相同的答案:50904個調查,這是不可能的。 – phper

+0

@phper優化器將您的LEFT JOIN轉換爲INNER JOIN。所以你的查詢基本上是一樣的。因此結果相同。 –

+0

Doh - 有一個金髮的時刻。固定 – symcbean

相關問題