从case语句解压缩表达式结果

时间:2017-12-22 02:55:15

标签: postgresql case

category 表中的四个类别。

id | name
--------------
1  | 'wine'
2  | 'chocolate'
3  | 'autos'
4  | 'real estate'

forecaster 表中众多(数千名)预报员中的两位。

id | name
--------------
1  | 'sothebys'
2  | 'cramer'

预报员对预测表中类别的相关预测。

| id | forecaster_id | category_id | forecast                                                     |
|----+---------------+-------------+--------------------------------------------------------------|
|  1 |             1 |           1 | 'bad weather, prices rise short-term'                        |
|  2 |             1 |           2 | 'cocoa bean surplus, prices drop'                            |
|  3 |             1 |           3 | 'we dont deal with autos - no idea'                          |
|  4 |             2 |           2 | 'sell, sell, sell'                                           |
|  5 |             2 |           3 | 'demand for cocoa will skyrocket - prices up - buy, buy buy' |

我想要(预测,类别,预测)的优先级映射,以便在某些主要预测者存在预测时(例如' cramer& #39; )使用它因为我更信任他。如果某些辅助预测者(例如' sothebys' )存在预测,请使用该预测。如果某个类别没有预测,请返回包含该类别的行,并返回null进行预测。

我有一些几乎可以工作的东西,在我得到逻辑后,我希望变成参数化查询。

select
    case when F1.category is not null
        then (F1.forecaster, F1.category, F1.forecast)
    when F2.category is not null 
        then (F2.forecaster, F2.category, F2.forecast)
    else (null, C.category, null)
    end
from 
    (
        select 
                FR.name as forecaster, 
                C.id as cid, 
                C.category as category, 
                F.forecast 
        from 
                forecast F 
                inner join forecaster FR on (F.forecaster_id = FR.id)  
                inner join category C on (C.id = F.category_id)
        where FR.name = 'cramer'
    ) F1
        right join (
        select 
                FR.name as forecaster, 
                C.id as cid, 
                C.category as category, 
                F.forecast  
        from 
            forecast F 
            inner join forecaster FR on (F.forecaster_id = FR.id)  
            inner join category C on (C.id = F.category_id)
        where FR.name = 'sothebys'
    ) F2 on (F1.cid = F2.cid)
    full outer join category C on (C.id = F2.cid);

这给出了:

'(sothebys,wine,"bad weather, prices rise short-term")'
'(cramer,chocolate,"sell, sell, sell")'
'(cramer,autos,"demand for cocoa will skyrocket - prices up - buy, buy buy")'
'(,"real estate",)'

虽然这是所需数据,但它是一列而不是三列的记录。 case是我能够找到的唯一方法,可以实现cramer下一个sothebys的排序,并且有很多重复。有没有更好的方法,如何将元组结果拉回到列中?

任何建议,特别是与删除重复或一般简化有关的建议表示赞赏。

1 个答案:

答案 0 :(得分:2)

这听起来像是DISTINCT ON(未经测试)的情况:

SELECT DISTINCT ON (c.id)
       fr.name AS forecaster,
       c.name AS category,
       f.forecast
FROM forecast f 
   JOIN forecaster fr ON f.forecaster_id = fr.id
   RIGHT JOIN category c ON f.category_id = c.id
ORDER BY 
   c.id, 
   CASE WHEN fr.name = 'cramer'   THEN 0 
        WHEN fr.name = 'sothebys' THEN 1
        ELSE 2 
   END;

对于每个类别,将选择订购中的第一行。由于Cramer比苏富比的id更高,因此会优先考虑。

如果您需要更复杂的排名,请调整ORDER BY子句。