【问题标题】:How to weight cols for each records using SQL only如何仅使用 SQL 为每条记录加权 cols
【发布时间】:2023-01-03 04:16:25
【问题描述】:

在 Postgresql 中,假设我有一个包含 3 条记录的 2-col 表,即 tA

id | col_A | col_B | type
1  | 1     | 2     | A  
2  | 3     | 4     | B
3  | 3     | 1     | A

和一个包含每种类型的列权重的表,名为tB

type | col   | weight
A    | col_A | 0.6
A    | col_B | 0.4
B    | col_A | 0.4
B    | col_B | 0.6

然后我想要一个与tA 大小相同的新表,但 cols 加权为 tB。例如,id=1,由于类型为A,因此为col_A*0.6col_B*0.4。预期结果如下

id | col_A | col_B | type
1  | 0.6   | 0.8   | A  
2  | 1.8   | 1.6   | B
3  | 1.2   | 0.4   | A

目前,我编写了一个 SQL 函数来处理,但我想知道是否有另一种方法可以在 SQL 查询中完成?

【问题讨论】:

    标签: sql postgresql inner-join aggregate-functions


    【解决方案1】:

    对于列名的固定列表,可以join,然后进行条件聚合以加权到每个值:

    select a.id, 
        a.col_a * max(b.weight) filter(where b.col = 'colA') col_a,
        a.col_b * max(b.weight) filter(where b.col = 'colB') col_b,
        a.type
    from ta a
    inner join tb b using (type)
    group by a.id
    

    这将过滤掉 ta 上的行,其类型在 tb 中不存在。如果担心,您可以改用left join

    【讨论】:

      【解决方案2】:

      考虑到未来可能会有两种以上的类型,可能有几十种,数据透视表将是完美的选择?为此,您需要 Postgres 附带的 tablefunc 扩展,因为它没有像 MS SQL Server 或 Oracle 中那样的本机支持。

      CREATE EXTENSION IF NOT EXISTS tablefunc;
      

      这使得 crosstab 数据透视表功能在您的数据库中可用。

      假设您的权重是 numeric 不受 IEEE 浮点精度问题影响的类型:

      SELECT tA.id
           , tA.col_A * ct.weight_A col_A
           , tA.col_B * ct.weight_B col_B
           , tA.type
        FROM tA
        JOIN crosstab('SELECT type, col, weight FROM tB ORDER BY type, col')
             AS ct(type text, weight_A numeric, weight_B numeric, weight_C numeric)
             USING (type)
       ORDER BY id
      ;
      

      根据需要更改为 double precisionreal。看到 crosstab 函数中的 SELECT 语句了吗?这基本上就是说,返回的第一列是您的行标识符,即您的分组。第二个返回的列是您要返回的列的名称。最后一个是上一列的值。所以 ct 变成了一个虚拟表,它改变了你的 tB 表,看起来像这样:

      type col weight
      A col_A 0.6
      A col_B 0.4
      B col_A 0.4
      B col_B 0.6

      看起来像这样:

      type weight_A weight_B weight_C
      A 0.6 0.4 [NULL]
      B 0.4 0.6 [NULL]

      请注意 weight_C 是如何从不存在于 tB 值中的?这没关系,而且很有用。这意味着只需对您的查询进行微小的更改,您就可以添加和删除列以反映 tB 的更改状态。例如,您可以添加 weight_Dweight_E 返回列。如果它们不在tB 中,它们将保持为 NULL,但如果您将适当的权重添加到 tB,它们将自动填充!

      这个计算表是您加入以获得最终答案的对象。

      【讨论】:

        猜你喜欢
        • 2023-03-05
        • 1970-01-01
        • 2014-10-20
        • 2012-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-29
        • 1970-01-01
        相关资源
        最近更新 更多