2016-08-02 34 views
0

我需要在表中爲每個ID設置一個「放棄」標誌,但最新結果不變。我以爲我有一個查詢將在這裏工作,但是當我在查詢上運行選擇時,我得到不正確的結果 - 我看到一個案例,它選擇了特定id的兩個結果。我也用相同的確切數據得到多個結果。 我在這裏做錯了什麼?SQL爲每個ID選擇除最新結果以外的所有內容

這裏是我的select語句:

select t.test_row_id, t.test_result_id, t.waived, t.pass, t.comment 
from EV.Test_Result 
join EV.Test_Result as t on EV.Test_Result.test_row_id = t.test_row_id and EV.Test_Result.start_time < t.start_time and t.device_id = 1219 and t.waived = 0 
order by t.test_row_id 

這裏的實際查詢我想運行:

update EV.Test_Result 
set waived = 1 
from EV.Test_Result 
join EV.Test_Result as t on EV.Test_Result.test_row_id = t.test_row_id and EV.Test_Result.start_time < t.start_time and t.device_id = 1219 and t.waived = 0 
+0

如果您有一個返回唯一時間戳(意味着至少是日期時間)的日期列,那麼使用MAX函數很容易。但是,如果不是......那麼也許是你的表結構中的設計缺陷。 –

+0

我們確實有一個datetime2的start_time列。我也嘗試了最大值,但是無法正確寫入。你有一個例子嗎?我不擅長SQL,這不是我的主要工作描述(儘管我正在努力學習!)。 – Johonn

+0

最後一個建議是使用縮進格式化查詢。 SQL忽略不在字符串中的內聯空間('THIS IS STRING IN SQL')(注意(')是SQL中的字符串分隔符) –

回答

1

如果我理解正確的這個,你是因爲ON謂詞的基數返回所有匹配的行有問題。

 EV.Test_Result.test_row_id = t.test_row_id 
    and EV.Test_Result.start_time < t.start_time 

ON將比較所有具有相同的ID和返回的結果集,其中START_TIME比t.start_time較小的每一個組合的START_TIME值。顯然,這不是你想要的。

    and t.device_id = 1219 
        and t.waived = 0 

這實際上是一個謂詞(ON技術就是其中之一),但我寧願在subquery/CTE使用這種有以下幾個原因:你限制SQL必須檢索和比較的行數。

類似下面的可能是你需要的東西:

SELECT A.test_row_id 
    , A.test_result_id 
    , A.waived 
    , A.pass 
    , A.comment 
FROM EV.Test_Result A 
INNER JOIN (SELECT MAX(start_time) AS start_time 
       , test_row_id 
      FROM EV.Test_Result 
      WHERE device_id = 1219 
       AND waived = 0 
      GROUP BY test_row_id 
          ) AS T ON A.test_row_id = T.test_row_id 
            AND A.start_time < T.start_time 
ORDER BY A.test_row_id 

該查詢然後返回在ON謂詞值之間的關係1:M,不像M:M查詢你已經用完。

UPDATE:

如你所知,你寫的: 因爲我不好意思地搞砸了試圖改變我的質疑SO,我將解釋基本SQL查詢經營者的物理和邏輯順序挽救自己一個簡單的SELECT聲明如下所示:

SELECT <aggregate column>, SUM(<non-aggregate column>) AS Cost 
FROM <table_name> 
WHERE <column> = 'some_value' 
GROUP BY <aggregate column> 
HAVING SUM(<non-aggregate column>) > some_value 
ORDER BY <column> 

請注意,如果您使用聚合函數,所有其他列必須出現在GROUP BY或其他功能。

現在,SQL Server需要它們被寫入的順序,雖然它實際上是由下面的順序,是值得記憶處理此邏輯:

  • FROM,WHERE,GROUP BY,HAVING,SELECT,ORDER BY

上有SELECT - MSDN發現了更多的細節,但是這就是爲什麼在SELECT運營商的任何列必須在group by或在聚合函數(SUMMINMAX等)...和也是爲什麼我的懶惰代碼失敗你第一次嘗試。 :/ 另請注意,ORDER BY是最後一個(技術上TOP運算符在此之後發生),沒有它的結果不確定,除非諸如DENSE_RANK之類的函數強制執行它(認爲這發生在SELECT語句中)。

希望這有助於解決問題,並且更好地瞭解SQL如何工作。乾杯

+0

oops,忘記指定該子查詢中的test_row_id。xD –

+0

感謝這個非常豐富的答案,它有助於更​​好地理解正在發生的事情。 我試過你的代碼,但在子查詢中的WHERE附近確實出現了語法錯誤。任何想法有什麼不對? – Johonn

+0

@Johonn LOL ... xD是... xD WHERE子句放錯了。 xD我需要記住在SO上改變我的查詢。 xD –

0

你可以嘗試ROW_NUMBER()函數時間戳降序排列,並篩選出具有ROW_NUMBER 1值;

下面的查詢應該獲取每個ID的所有記錄,除了最新的一個

我想下面的查詢在Oracle中有字段的表:ID,USER_ID,record_order ADN時間戳和它的工作:

select 
      <table_name_alias>.* 
     from 
     (
    select 
    id, 
    user_id, 
     row_number() over (partition by id order by record_order desc) as record_number 
    from 
    <your_table_name> 
) <table_name_alias> 
     where 
    record_number <>1; 

如果您正在使用Teradata DB,則還可以嘗試QUALIFY語句。我不確定是否所有的DB都支持這一點。

Select 
    table_name.* 
    from table_name 
    QUALIFY row_number() over (partition by id order by record_order desc) <>1; 
+0

感謝您的回答。假設「RANK」是一個新表(排名似乎是一個保留字),我仍然無法使上述工作 - 最後一行對我產生錯誤:「期望的AS,ID或QUOTED_ID」(用於WHERE )和「無效列名稱r」(我用r代替RANK) – Johonn

+0

@Johon這個錯誤是因爲派生表需要一個別名。 RANK是一個保留字。 RowNum或R會有更好的選擇。 –

+0

@Johonn: ü可以試試下面的查詢,在Oracle 沒有工作對我來說 '從 選擇table1 *(選擇ID,USER_ID,ROW_NUMBER()以上(分區由ID順序 通過record_order DESC)作爲record_name number TABLE_NAME where record_number <> 1;' 如果您使用的是Teradata DB,您也可以嘗試使用QUALIFY語句。我不確定是否所有的DB都支持這一點。 'Select * from table_name QUALIFY row_number()over(按ID順序分區 by record_order desc)<> 1;' – Leo

相關問題