Postgresql
當列的類型不同時,Postgres 中是否有任何方法可以參數化排序順序列的過程?
我正在嘗試編寫一個函式來執行(一些複雜的事情)並根據參數以不同的順序返回結果。
簡化版本如下所示:
CREATE OR REPLACE FUNCTION test(order_column text) RETURNS TABLE(thing1 bigint,thing2 text, thing3 timestamp without time zone) LANGUAGE 'plpgsql' AS $BODY$ BEGIN RETURN QUERY SELECT thing1, thing2::text, thing3 FROM some_table ORDER BY CASE WHEN order_column='id' THEN thing1 ELSE thing3 END DESC; END; $BODY$;
不幸的是,thing1 是一個 bigint,而 thing3 是一個時間戳,當我嘗試執行該函式時,我收到一個錯誤,說 bigint 和時間戳類型無法匹配,我將其解釋為從案例返回的類型需要是相同(或至少兼容)。我不能將它們都轉換為文本,因為值的範圍沒有正確排序。
我嘗試返回列號而不是列名 - 這至少會執行,但它會忽略列順序(在函式中或僅作為簡單語句執行)。例如,
SELECT * FROM some_table ORDER BY 1;
工作正常但
SELECT * FROM some_table ORDER BY CASE WHEN TRUE THEN 1 ELSE 2 END;
不按第 1 列排序
我的解決方法是
if column_order='first' then (masses of complex stuff) SELECT ... ORDER BY thing1 else (masses of complex stuff, duplicated) SELECT ... ORDER BY thing3 end if;
但這太可怕了,我真的希望有其他方法可以解決這個問題,而且我目前缺少一些東西。
有什麼辦法可以做我想做的事嗎?
小心條件排序,它可能會創建錯誤的查詢計劃,有時會強制進行表掃描。如果過濾和連接子句,或者只是實際數據的大小,意味著您最後有少量行要排序,那麼這不是問題,這樣的事情會起作用:
ORDER BY CASE WHEN ordering_column = 'id' THEN id ELSE NULL END , CASE WHEN ordering_column = 'timestamp' THEN timestamp ELSE NULL END
事實上它無論如何都會起作用,它可能只是對於大量數據來說效率低下。
對於較大的輸出,您的解決方法可能更有效,因為它可以更好地利用索引進行排序。另一種選擇是有兩個過程,一個用於每個排序,或者根據需要呼叫每個過程,或者讓您的主過程呼叫其他過程,具體取決於它在參數中傳遞的排序順序。根據 postgres 如何處理過程的記憶體查詢計劃,這可能$$ † $$避免將一個案例的記憶體計劃用於另一個效率低得多的案例。
$$ † $$我根本不是 pg 內部的專家,但是由於這種原因,單個“廚房水槽”過程和具有條件排序等的查詢可能會成為 SQL Server 中的性能殺手。