2

これが私のSQLクエリです:


SELECT (CASE (elapsed_time_from_first_login IS NULL) 
                        WHEN true THEN 0 
                        ELSE elapsed_time_from_first_login END) 
FROM (
   SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) 
   FROM radacct
   WHERE UserName = 'test156') AS elapsed_time_from_first_login;

上記のクエリを実行すると、次のエラーが発生します。

エラー: CASE タイプのレコードと整数が一致しません

エラーメッセージから、 ( min() 関数のため)常に単一の値であってもPostgreSQL、2番目の選択をそれぞれ行として取ることがわかります。elapsed_time_from_first_login

質問:このクエリを処理する方法について何か提案はありますか?

4

4 に答える 4

3

あなたが実際にやろうとしていることは、次のようになるはずです。

SELECT COALESCE((
    SELECT now() - min(AcctStartTime)
    FROM   radacct
    WHERE  userName = 'test156'), interval '0s')

副選択 (エイリアスを使用elapsed_time_from_first_login) で行が見つからない場合は、NULL 値が返されますが、は返されません。

これをキャッチするwhole sub-selectには、COALESCEステートメントでラップします。これはCASE、目的よりも簡単です。

min()最初は「行なし」を に変換する集計関数を見落としていましたNULL。したがって、副選択に集約関数がある限り、以下の単純な形式でも同じように機能します。効果を示す sqlfiddleの簡単なデモを次に示します。

あなたのクエリに関する他の問題はすでに指摘されています。しかし、これははるかに簡単な解決策です。intervalではなくを返しますinteger


整数に変換

@artaxerxe によるコメントの後、簡素化されました。
単純なフォームは、「行なし」をチェックせずにジョブを実行します。

SELECT COALESCE(EXTRACT(epoch FROM now() - min(AcctStartTime))::int, 0)
FROM   radacct
WHERE  userName = 'test156';

詳細についてEXTRACT(epoch FROM INTERVAL) はマニュアルを参照してください。

集計関数と NULL

もう1つ注意:最初の質問で使用したのとは異なり、集計関数を使用した場合、結果は異なりcount()ます。を返さないという点で、標準の集約関数の中で特殊なケースです。値 (または行) が見つからない場合は、代わりに返されます。sum()count()NULL0

集計関数に関するマニュアルからのこの抜粋は、それをかなりカバーしているようです:

count を除いて、行が選択されていない場合、これらの関数は null 値を返すことに注意してください。特に、sum of no rows は予想されるゼロではなく null を返し、入力行がない場合、array_agg は空の配列ではなく null を返します。合体関数を使用して、必要に応じて null をゼロまたは空の配列に置き換えることができます。

于 2012-08-09T07:52:51.763 に答える
2

Postgres はとが同じタイプではない0と不平を言っています。elapsed_time_from_first_login

これを試してください(また、選択を簡素化します):

select
    coalesce(elapsed_time_from_first_login::INT4, 0)
from ...
于 2012-08-09T07:06:38.053 に答える
1

2 つ目は、1 つの列と 1 つの行SELECTで名前が付けられたテーブルを返します。elapsed_time_from_first_loginその列に別名を付けて、CASE句で使用する必要があります。値が期待される場所にテーブル全体 (1 つの列、1 つの行のみであっても) を配置することはできません。

SELECT (CASE (elapsed_time IS NULL) 
                        WHEN true THEN 0 
                        ELSE elapsed_time end) 
   FROM (SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) 
                AS elapsed_time                -- column alias
         FROM radacct 
         WHERE UserName = 'test156'
        ) as elapsed_time_from_first_login;    -- table alias

CASE関数を使用してを短縮できCOALESCE()ます (オプションで、結果に表示される列のエイリアスを追加します)。

SELECT COALESCE(elapsed_time, 0) 
         AS elapsed_time 
   FROM (SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) 
                AS elapsed_time            
         FROM radacct 
         WHERE UserName = 'test156'
        ) as elapsed_time_from_first_login;    -- table alias
于 2012-08-09T07:38:28.140 に答える
1

これが私がフォーマットした方法でありSQL、現在は機能しています:

SELECT 合体(結果, 0)
     FROM (SELECT (now()::ABSTIME::INT4 - min(AcctStartTime)::ABSTIME::INT4) as result
                FROM radacct WHERE UserName = 'test156') aslapse_time_from_first_login;
于 2012-08-09T07:12:56.793 に答える