2014-04-02 47 views
1
  1. 是否有可能做一些像SQL以下,不PL/pgSQL的(注意,如果是唯一可能與PL/pgSQL裏,那麼如何)?PostgreSQL的:CASE:從兩個不同的表

    IF password = 'swordfish' THEN 
        SELECT a, b, c FROM users; 
    ELSE 
        SELECT -1; -- unauthorized error code 
    END IF; 
    
  2. 理想情況下,我可以包裝在一個函數的上面TRUE作爲一個參數?

  3. 相反,是否可以將command status string設置爲-1?

我在問這是因爲我想查詢返回一個錯誤代碼,如-1,如果有人試圖獲取所有用戶使用錯誤密碼的列表。這是用於具有每個都有密碼的用戶帳戶的Web應用程序。所以,這不是我想用數據庫角色/權限管理的東西。

+0

將真真正是什麼樣的?此外,您在兩個分支中返回不同數量的列將無法工作。 –

+0

@trygvis我更新了我的問題。好。也許應該改變第二個'SELECT'爲'-1,NULL,NULL'? – ma11hew28

+0

@trygvis一個簡單的'SELECT'不會返回到任何地方。提供的例子是有效的pl/pgsql,只是沒有做任何事情。 – pozs

回答

0

算法

  1. 選擇1a(授權),如果我們找到一個user_id_1 - session_id比賽。
  2. 選擇0, NULL, NULLu(授權),如果我們沒有找到在步驟1中
  3. 選擇user_id, body, sent匹配到s(選擇),如果我們確實發現在步驟1中
  4. 聯盟us匹配。

代碼

-- List messages between two users with `user_id_1`, `session_id`, `user_id_2` 
CREATE FUNCTION messages(bigint, uuid, bigint) RETURNS TABLE(i bigint, b text, s double precision) AS 
$$ 
    WITH a AS (
     SELECT 1 
     FROM sessions 
     WHERE user_id = $1 
     AND id = $2 
    ), u AS (
     SELECT 0, NULL::text, NULL::double precision 
     WHERE NOT EXISTS (SELECT 1 FROM a) 
    ), s AS (
     SELECT user_id, body, trunc(EXTRACT(EPOCH FROM sent)) 
     FROM messages 
     WHERE EXISTS (SELECT 1 FROM a) 
     AND chat_id = pair($1, $3) 
     LIMIT 20 
    ) 
    SELECT * FROM u UNION ALL SELECT * FROM s; 
$$ 
LANGUAGE SQL STABLE; 
0

除(pl/pgsql only)CASE control structure之外,還有一個CASE expression

編輯CASE expression在SQL方面:

SELECT CASE 
      WHEN my_conditions_are_met THEN a 
      ELSE NULL 
     END AS a_or_null, 
     b, 
     c 
FROM users; 

編輯2:給your example這就是你可以在純SQL做到這一點:

WITH params AS (
    SELECT user_auth(:user_id, :key)  AS user_auth, 
      pair(:user_id, :with_user_id) AS chat_id 
), error_message AS (
    SELECT -1         AS "from", 
      'auth error'       AS "body", 
      EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) AS "sent" 
) 
SELECT from, body, trunc(EXTRACT(EPOCH FROM sent)) 
FROM messages 
JOIN params ON messages.chat_id = params.chat_id AND params.user_auth 
UNION ALL 
SELECT error_message.* 
FROM error_message 
JOIN params ON NOT params.user_auth 
+0

我知道,但你會如何使用它來做我在問什麼? – ma11hew28

+0

如果你需要確保所有的值都是NULL,這是一種痛苦,但如果只有錯誤代碼需要特定的值,它才能很好地工作。 –

+0

就是這樣。但爲什麼返回錯誤代碼就像普通結果呢?所有客戶端都必須具有某種形式的錯誤處理,受影響的行計數,這是更好的方式。 – pozs

0

這是可行的,但它是不漂亮:

WITH 
    u AS (SELECT * FROM user WHERE mail = '..'), 
    code AS (
    SELECT 
     CASE (SELECT count(*) FROM u) 
     WHEN 0 THEN 
     'not found' 
     ELSE 
     CASE (SELECT count(*) FROM u WHERE password = '..') 
     WHEN 1 THEN 
      'right password' 
     ELSE 
      'wrong password' 
     END 
     END) 
SELECT 
    code.*, 
    u.* 
FROM code NATURAL LEFT OUTER JOIN u 

我想你可能想看看創建一個結果集返回函數。

+0

有趣......謝謝。不過,這會返回每行的代碼。有沒有辦法與PL/pgSQL做到這一點,其中函數將只返回錯誤代碼或結果,但不是兩者? – ma11hew28

+0

我想[我想通過](http://stackoverflow.com/a/22816804/242933)如何用PL/pgSQL來做我想要的。 – ma11hew28

+1

@MattDiPasquale是的,這可能是最好的解決方案。 –

0

下面的PL/pgSQL函數返回user_id & with_user_id之間發送的messages如果user_idkey對被授權,如由用戶定義的函數(UDF)user_auth確定。否則,返回一行from = -1。另一個UDF,pairunique unordered pairing function,給定兩個用戶ID,返回消息所屬的chat_id

--- Arguments: user_id, key, with_user_id 
CREATE FUNCTION messages(bigint, uuid, bigint) 
RETURNS TABLE(from bigint, body text, sent double precision) AS $$ 
BEGIN 
    IF user_auth($1, $2) THEN 
     RETURN QUERY SELECT from, body, trunc(EXTRACT(EPOCH FROM sent)) 
        FROM messages WHERE chat_id = pair($1, $3); 
    ELSE 
     i := -1; 
     RETURN NEXT; 
    END IF; 
END; 
$$ LANGUAGE plpgsql STABLE; 

我不知道如何將其轉換爲SQL函數或者是否會更好。

+0

變量'i'沒有在該範圍內定義,'RETURN NEXT;'不會返回任何東西(在ELSE分支中將返回一個空結果集) - 使用類似'RETURN NEXT ROW(-1, 'auth error',EXTRACT(EPOCH FROM CURRENT_TIMESTAMP));' – pozs