【问题标题】:Reuse SUM OVER PARTITION return value in query在查询中重用 SUM OVER PARTITION 返回值
【发布时间】:2017-12-09 23:28:09
【问题描述】:

我正在寻找一种方法来避免在查询中执行两次计算,例如:

SELECT DISTINCT
    coins.price_btc,
    coins.price_eur,
    coins.price_usd,
    coins.currency_name,
    coins.currency_symbol,
    SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_eur AS holdings_eur,
    SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_usd AS holdings_usd,
    SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_btc AS holdings_btc,
    SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) AS holdings 
FROM
    market_transactions
    INNER JOIN coins ON coins.id = market_transactions.market_coin_id 
WHERE
    market_transactions.user_id = 1 
ORDER BY
    coins.currency_symbol

我不确定分区总和是否一直在运行。

感谢任何指点,我确信查询也可以优化,但我不确定从哪里开始。

CREATE TABLE "public"."coins" (
  "id" int8 NOT NULL DEFAULT nextval('coins_id_seq'::regclass),
  "currency_symbol" text COLLATE "pg_catalog"."default" NOT NULL DEFAULT NULL,
  "currency_name" text COLLATE "pg_catalog"."default" NOT NULL DEFAULT NULL,
  "price_usd" numeric(16,7) NOT NULL DEFAULT NULL,
  "price_eur" numeric(16,7) NOT NULL DEFAULT NULL,
  "price_btc" numeric(16,7) NOT NULL DEFAULT NULL,
  CONSTRAINT "coins_pkey" PRIMARY KEY ("id")
)

CREATE TABLE "public"."market_transactions" (
  "id" int8 NOT NULL DEFAULT nextval('market_transactions_id_seq'::regclass),
  "user_id" int4 NOT NULL DEFAULT NULL,
  "quantity" numeric(18,8) NOT NULL DEFAULT NULL,
  "market_coin_id" int4 DEFAULT NULL,
  CONSTRAINT "market_transactions_pkey" PRIMARY KEY ("id")
)

一个用户有许多涉及硬币的交易(market_transactions.market_coin_idcoins.id),我试图将每个交易的拥有数量(market_transactions.quantity)相加,然后将该值乘以表示的硬币价格以不同的货币(btc、eur、usd)

【问题讨论】:

  • 请分享表结构、示例数据、预期输出以及查询尝试生成的结果的描述。作为一般经验法则,每当我看到 SELECT DISTINCT 和 Window 函数时,我都会怀疑查询的逻辑正确性。
  • 感谢您的检查,我添加了简化的表结构,插入需要一些时间,但应该很容易。

标签: sql postgresql


【解决方案1】:

我建议在joining 和做之前聚合:

SELECT c.*,
       mt.quantity * c.price_eur AS holdings_eur,
       mt.quantity * c.price_usd AS holdings_usd,
       mt.quantity * c.price_btc AS holdings_btc,
       mt.quantity * c.market_coin_id AS holdings 
FROM coins c JOIN
     (SELECT mt.market_coin_id, SUM(mt.quantity) as quantity
      FROM market_transactions t
      WHERE mt.user_id = 1 
      GROUP BY mt.market_coin_id
     ) mt
     ON c.id = mt.market_coin_id 
ORDER BY c.currency_symbol

【讨论】:

    【解决方案2】:

    对查询运行 EXPLAIN(即 EXPLAIN SELECT DISTINCT ...)并查看查询计划是什么。最有可能的是,它只运行一次窗口函数。如果它多次运行,请尝试添加外部 SELECT:

    SELECT DISTINCT 
      price_btc, 
      price_eur, 
      price_usd, 
      currency_name,
      currency_symbol,
      holdings * price_eur AS holdings_eur,
      holdings * price_usd AS holdings_usd,
      holdings * price_btc AS holdings_btc,
      holdings
    FROM (
        SELECT
        coins.price_btc,
        coins.price_eur,
        coins.price_usd,
        coins.currency_name,
        coins.currency_symbol,
        SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) AS holdings 
    FROM
        market_transactions
        INNER JOIN coins ON coins.id = market_transactions.market_coin_id 
    WHERE
        market_transactions.user_id = 1 
    ) src
    ORDER BY
        currency_symbol
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-29
      • 1970-01-01
      • 1970-01-01
      • 2019-10-30
      • 1970-01-01
      • 2021-12-30
      • 2017-11-22
      相关资源
      最近更新 更多