【问题标题】:Multiple SQL queries in one function一个函数中的多个 SQL 查询
【发布时间】:2018-05-15 19:03:15
【问题描述】:

我需要在我的 postgresql 数据库上的单个 SQL 查询中返回多个值。到目前为止,这是我的查询:

SELECT AVG("percent"), MIN("percent"), MAX("percent"), AVG("profit"), MIN("profit"), MAX("profit")
FROM public.log_analyticss 
WHERE "buyPlatform" = 'platA' AND
"date" >= '1526356073.6126819'

数据

date             sellPlatform     profit      percent    
----------       ------------     ----------  ----------
1526356073.61    platA            0           10.1
1526356073.62    platA            22          11
1526356073.63    platA            3           7
1526356073.64    platA            1           8
1526356073.65    platA            11          9
1526356073.66    platA            12          10
1526356073.67    platA            13          15

想要的结果

date             sellPlatform     profit      percent    
----------       ------------     ----------  ----------
1526356073.61    platA            0           10.1         //MIN Profit
1526356073.62    platA            22          11           //MAX Profit
1526356073.63    platA            3           7            //MIN Perc
1526356073.67    platA            13          15           //MAX Perc

//然后不知何故,我希望它也返回 AVG,如果这是可能的话。否则,我不介意运行另一个查询来做到这一点。

问题是我不只是想要 MIN 和 MAX 值。我想要从中获取 MIN 和 MAX 值的整行数据。

我知道我要求的是 AVG 和 MIN/MAX 值,它将以两种不同的格式返回数据。我知道这可能是不可能的。但是任何关于如何最有效地做到这一点的帮助都会非常有帮助。

现在我只是将整个数据集拉入我的代码并计算我的代码中的平均值、最小值和最大值,我知道这是否非常糟糕并且非常慢。该表有大约 800 万行,我正在抓取的数据集大约有 9000 行,所以我现在这样做的方式非常慢。

【问题讨论】:

  • 发布样本数据的预期结果
  • mix 的结果行应该不同于 max .. 你想要这些结果吗? .. 显示适当的数据样本和预期结果
  • @RadimBača 我刚刚添加了一个示例数据集和结果

标签: php sql database postgresql


【解决方案1】:

检索与最小值/最大值关联的行的最有效方法通常根本不涉及MIN()/MAX() 聚合;相反,您可以将ORDER BY 附加到查询中,然后添加LIMIT 1 以仅获取第一条记录。

这意味着您需要四个具有四种不同顺序的 SELECT 语句,但您可以将昂贵的部分(从 log_analyticss 提取)分解为 temp tableCTE,例如:

WITH Data AS (
  SELECT *
  FROM public.log_analyticss 
  WHERE "buyPlatform" = 'platA' AND
    "date" >= '1526356073.6126819'
)
(SELECT 'Min percent', * FROM Data ORDER BY "percent" ASC LIMIT 1)
UNION ALL
(SELECT 'Max percent', * FROM Data ORDER BY "percent" DESC LIMIT 1)
UNION ALL
(SELECT 'Min profit', * FROM Data ORDER BY "profit" ASC LIMIT 1)
UNION ALL
(SELECT 'Max profit', * FROM Data ORDER BY "profit" DESC LIMIT 1)

在您的情况下,临时表可能比 CTE 更好,因为您可以重复使用它来计算平均值。

请注意,如果这些最大值/最小值之一由两个不同的行共享,则此查询将仅返回其中一个。所选行是随机有效选择的,但您可以将更多字段附加到 ORDER BY 子句以充当决胜局。

如果您在这种情况下确实需要两条记录,您将需要更像 Auston 或 Radim 的答案,即首先计算聚合,然后重新连接到 profitpercent 列上的数据。您仍然可以在此处使用临时表/CTE,以避免多次点击log_analyticss

【讨论】:

  • 我也不太担心重复。如果有重复,那么我不在乎返回哪一个重复
  • 我试图将此功能添加到末尾,但它没有工作UNION ALL (SELECT 'Avg Profit', AVG("profit") FROM Data ) 任何关于我如何为利润和百分比执行此操作的想法。它给出了错误each UNION query must have the same number of columns
  • 绝对是迄今为止最好的答案。如果可能的话,我只想添加 AVG 功能。否则,我将只为 AVG 功能运行第二个命令。你知道我将如何使用同一个数据变量/临时表来运行 AVG 函数吗?
  • @Nevin:UNION 的每个分支都需要具有相同的字段集。平均值并不适合这里,因为它没有相关的记录。如果您决定将所有这些都塞进同一个数据结构中,则需要将其填充,使其看起来像 log_analyticss 行,例如SELECT 'Avg', NULL AS "date", NULL AS "sellPlatform", AVG("profit") AS "profit" AVG("percent") AS "percent"。请注意,字段顺序需要与其他子查询完全匹配。
  • 也就是说,找到超过 9000 条记录的最大/最小记录 - 即使您在客户端代码中执行此操作 - 最多也需要几毫秒。如果这需要 7 秒的时间来运行,那么它可能会花费 99% 的时间从log_analyticss 进行初始获取(如果是这样,这就是您应该专注于优化的内容)。表中是否有buyPlatformdate 上的indexes
【解决方案2】:

你需要一些类似的东西:

SELECT a.*
FROM public.log_analyticss  a
JOIN
(
    SELECT 
        MIN("percent") min_percent, 
        MAX("percent") max_percent, 
        MIN("profit") min_profit, 
        MAX("profit") max_profit
    FROM public.log_analyticss 
) t ON a.date = t.date AND
       a.sellPlatform = t.sellPlatform AND
       (a.profit = minprofit OR
        a.profit = maxprofit OR
        a.percent = minpercent OR
        a.percent = maxpercent)

【讨论】:

    【解决方案3】:

    我认为最好的方法是通过两个查询: 第一个检索指标,就像您所做的一样; 第二个查询检索样本寄存器。

    或者您可以尝试在临时表上运行(结束会话后自动删除):

    CREATE TEMP TABLE statistics AS 
        SELECT AVG(percent) as perc_avg, MIN(percent) as perc_avg, MAX(percent) as perc_max, AVG(profit) as pro_avg, MIN(profit) as pro_min, MAX(profit) as pro_max
        FROM public.log_analyticss 
        WHERE buyPlatform = 'platA' AND
        sellPlatform = 'platB' AND 
        productId = '183948' AND
        date >= '1526356073.6126819'
    ;
        SELECT date, sellPlatform, profit, percent
        FROM public.log_analyticss a join statistics s
         on (a.profit = s.pro_max or a.profit = s.pro_min or
             a.percent = s.perc_max or a.percent = s.perc_min)
        WHERE buyPlatform = 'platA' AND
        sellPlatform = 'platB' AND 
        productId = '183948' AND
        date >= '1526356073.6126819';
    

    对临时表的引用: http://www.postgresql.org/docs/9.2/static/sql-createtable.html

    【讨论】:

    • 当我这样做时 SELECT AVG("percent"), MIN("percent"), MAX("percent"), AVG("profit"), MIN("profit") 它只给我利润或百分比的最小值、最大值和平均值,而不是两者
    • 我认为在这种情况下,您需要两个临时的 1 来百分比和其他来获利。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    相关资源
    最近更新 更多