2012-08-14 52 views
0

爲了更清楚:觸發一個行的一列的更新如果選擇部分匹配該行的列中的一

thetable(id int, username varchar(30), password varchar(30), last_successful_login timestamp, last_unsuccessful_login timestamp, another_variable varchar(30))具有下列行:(1,「TGH」,「傳」,0,0, 「其他」)

1)錯誤的用戶/密碼對,但與用戶名行

我想select id from thetable where username="tgh" and password="wrongpass" and another_variable="another";更新所有的last_unsuccessful_login列ŧ他排列着username="tgh"another_variable="another"(這是唯一的,不能有兩行(「tgh」,「另一個」))。可以有(「tgh」,「another2」)。)到CURRENT_TIMESTAMP

所以行的例子是(1, "tgh", "pass", 0, CURRENT_TIMESTAMP, "another")後「選擇」查詢沒有完全比賽。根據選擇的結果,我試圖避免在表格上僅運行username="tgh"another_variable="another"的額外更新,即update thetable set last_unsuccessful_login=CURRENT_TIMESTAMP where username="tgh" and another_variable="another";

2)正確的用戶/密碼對

而且,如果所有的三個usernamepasswordanother_variable比賽,這次我想設置的last_successful_loginCURRENT_TIMESTAMP

這將使行的例子中`(1, 「TGH」, 「通」,CURRENT_TIMESTAMP,0, 「另一個」)

什麼是最有效的方式做到這一點?

+0

什麼是你的表格結構? ('SHOW CREATE TABLE thetable'的結果)你想要什麼樣的觸發器:INSERT,UPDATE或DELETE? – Jocelyn 2012-08-14 22:23:00

+0

我想我已經在問題中明確了所有問題,包括你問的問題。 – Etherealone 2012-08-14 23:55:02

+0

你沒有。我不發表評論的樂趣。你的問題沒有說明你的表結構是什麼。而要理解你想做什麼幾乎是不可能的。另外,你的問題並沒有清楚地顯示你所嘗試過的。您有權拒絕更新您的問題。但是,不要驚訝沒有人可以幫助你或想幫助你。 – Jocelyn 2012-08-15 08:01:43

回答

1

您的問題的簡短答案是否定的,這是不可能的SELECT語句導致或觸發更新。 (這裏需要注意的是SELECT語句可以調用可以執行UPDATE的FUNCTION(MySQL存儲程序)。)

你不能繞過發佈UPDATE語句; UPDATE語句必須從某處發出,而SELECT語句不能「觸發」它。

它可能有一個UPDATE語句來完成對在密碼欄中的當前值提供密碼的檢查,同時設置last_successful_login和last_unsuccessful_login列,如:

UPDATE thetable 
    SET last_successful_login = 
     IF(IFNULL(password,'')='wrongpass',CURRENT_TIMESTAMP,0) 
    , last_unsuccessful_login = 
     IF(IFNULL(password,'')='wrongpass',0,CURRENT_TIMESTAMP) 
WHERE username='tgh' 
    AND another_variable='another' 

所以,你可以首先發布UPDATE語句;然後發出一個SELECT語句。

如果您想最大限度地減少數據庫「往返」的數量,但需要額外的複雜性(使其他人更難以弄清楚發生了什麼),您可以將UPDATE語句放入存儲的程序中。如果你把它放到函數中,你可以設置返回值來指明登錄是否成功。

SELECT udf_login('username','wrongpass','another') 

所以,從你的應用程序,它看起來像你正在做一個登錄檢查,但被調用的函數可以執行更新。

CREATE FUNCTION `udf_login` 
(as_username   VARCHAR(30) 
, as_password   VARCHAR(30) 
, as_another_variable VARCHAR(30) 
) RETURNS INT 
READS SQL DATA 
BEGIN 
    UPDATE `thetable` 
     SET `last_successful_login` = 
      IF(IFNULL(`password`,'')=IFNULL(as_password,''),CURRENT_TIMESTAMP,0) 
     , `last_unsuccessful_login` = 
      IF(IFNULL(`password`,'')=IFNULL(as_password,''),0,CURRENT_TIMESTAMP) 
    WHERE `username` = as_username 
     AND `another_variable` = as_another_variable; 

    -- then perform whatever checks you need to (e.g) 
    --  SELECT IFNULL(t.password,'')=IFNULL(as_password,'') AS password_match 
    --  FROM `thetable` t 
    --  WHERE t.username = as_username 
    --  AND t.another_variable = as_another_variable 
    -- and conditionally return a 0 or 1 
    RETURN 0; 
END$$ 
+0

第二個想法很好。 SQL服務器位於遠程計算機上。我知道這不是一個好主意,但認證不會被執行_that_經常會引發問題(如果我能找到一種方法來擺脫一些額外的UPDATE語句當然)。但是,使用第二種方法,我可以將很多事情放入一個查詢中,而不僅僅是UPDATE。另外,我認爲它不會佔用數據庫資源,因爲不會對所有查詢進行某種類型的觸發器檢查。謝謝。 – Etherealone 2012-08-21 20:39:00

+1

@Tolga:是的,如果你有幾個需要作爲一個組運行的SQL語句,那麼將它們一起放到MySQL數據庫中的「存儲程序」中可能會更有效率,因爲它可以減少「roundtrips」之間的往返次數客戶端和服務器。 (注意:'READS SQL DATA'是一個kludge,在創建函數時避開MySQL錯誤,函數實際上是MODIFIES SQL DATA。實際上你可能想調用一個使用OUT參數的存儲過程來返回一個值。 – spencer7593 2012-08-22 02:52:01

相關問題