2014-03-28 58 views
2

我正在嘗試編寫一個查詢,該查詢查找具有特定代碼的人員最近一段時間(年),但如果他們有另一段時間代碼與最新的時期(年)。我會明白,所以我的例子是有道理的。編寫查詢以包含某些值但在查找最新時間段時排除其他值

我希望擁有代碼A1,A2,A3,A4,A5而不是AG,AP,AQ的人。有些人在一段時間內(如2014年)擁有A1代碼,並且在同一時期擁有AG代碼。我想排除他們。並非每個人都有代碼,因此字段值可能爲NULL

有沒有一種方法可以用不同的方式表達這個(比如少個字符)呢?

SELECT 
    people.firstName 
FROM 
    people 
WHERE EXISTS (
    SELECT * 
    FROM codes 
    WHERE 
     codes.people_id = people.id 
     AND period = (SELECT MAX(period) FROM codes codes2 WHERE codes2.people_id = codes.people_id) 
     AND code LIKE 'A[1-5]' 
) 
AND NOT EXISTS (
    SELECT * 
    FROM codes 
    WHERE 
     codes.people_id = people.id 
     AND period = (
      SELECT MAX(period) 
      FROM codes codes2 
      WHERE codes2.people_id = codes.people_id 
     ) 
     AND code LIKE 'A[GPQ]' 
) 

架構如下:

人民

  • ID(PK)
  • 的firstName

代碼

  • people_id(FK)與People的多對一​​關係表
  • 代碼(例如, 「A1」, 「A2」, 「公司」)
  • 時期(如 「2013」​​, 「2014」)
+0

您的查詢是否提供了正確的結果? –

+1

你能否提供涉及的模式? –

+0

我的查詢確實給了我正確的結果,但我想知道如果我可以用更有效的方式寫它。 – user3473043

回答

0

有這麼多的方法,你能做到這一點,我不是一個SQL專家,但我看不到您的查詢太糟糕了,如果您想嘗試減少可以考慮使用GROUP BY clause以及SUMAggregate functionHAVING clause中的子查詢數量。

我開始更新你的代碼如下:

SELECT 
    people.firstName 
FROM 
    people 
    LEFT JOIN codes AS a15 ON a15.people_id = people.id AND a15.code LIKE 'A[1-5]' 
    LEFT JOIN codes AS agpq ON agpq.people_id = people.id AND agpq.code LIKE 'A[GPQ]' 
GROUP BY 
    people.firstName 
HAVING 
    SUM(CASE WHEN a15.code IS NULL THEN 0 ELSE 1 END) > 0 
    AND SUM(CASE WHEN agpq.code IS NULL THEN 0 ELSE 1 END) = 0 

然而,這並不考慮任何與描述時期的具體要求做。您可以將期限添加到GROUP BY條款或將其添加到WHERE或其中一個JOIN約束條件中,但我從您的描述中確切無法確定您的要求(我不相信這是您的任何錯誤自己,我只是不能親自調整提供給描述的代碼)。

我還想指出上面的SUM函數不會給出匹配代碼數的精確計數。這是因爲如果A[GPQ]A[1_5]都返回至少一行,則每個約束返回的數字將乘以爲另一個返回的數字,但它可以用來確定是否存在「任何」返回項目,就像標準一樣是匹配它將有一個SUM(...) > 0

我敢肯定,一個更有經驗的SQL Developer/DBA將能夠戳我提出的查詢中的很多洞,但它可能會給他們或別人的東西工作,並希望給你的想法以替代使用子查詢。

相關問題