【问题标题】:Each UNION SELECT working fine, but throwing an error upon UNION每个 UNION SELECT 工作正常,但在 UNION 上抛出错误
【发布时间】:2019-02-05 14:45:16
【问题描述】:

希望有人可以通过 2 个查询的 UNION 帮助 MariaDB 10.3 的初学者。

以下每个查询都可以正常工作,但是当我想在 UNION 中组合结果时,它会引发“除以 0”警告。

SQL 1:

    WITH hv_sub AS (SELECT hv.portfolio,
                                    hv.price_date,
                                    SUM(hv.VALUE) AS curValue,
                                    SUM(hv.VALUE) + IFNULL(SUM(tv.cashflow),0) AS netValue,
                                    SUM(hv.retrn) AS portfolio_retrn
                            FROM holdings_VIEW_day_by_day hv
                                LEFT JOIN transactions_VIEW tv ON tv.tr_date = hv.price_date AND hv.portfolio = tv.portfolio AND hv.isin = tv.isin
                            WHERE hv.isin <> 'EU0000000000'
                            GROUP BY hv.portfolio, hv.price_date
                            ORDER BY hv.price_date),

            portfolio_retrn_pct AS (SELECT hv_sub.portfolio,
                                                        hv_sub.price_date,
                                                        hv_sub.portfolio_retrn,
                                                        hv_sub.netValue / LAG(hv_sub.curValue,1) OVER (PARTITION BY hv_sub.portfolio ORDER BY hv_sub.price_date) AS portfolio_retrn_pct
                                                FROM hv_sub)

    SELECT prp.portfolio,
                'Portfolio',
                CAST(YEAR(prp.price_date) AS CHAR) AS yr,
                CONCAT(ROUND(100*(EXP(SUM(LN(prp.portfolio_retrn_pct)))-1),1),"%") AS portfolio_twRoR,
                SUM(prp.portfolio_retrn) AS portfolio_retrn,
                0 AS yrEndValue
        FROM portfolio_retrn_pct prp
        GROUP BY prp.portfolio, YEAR(prp.price_date)

SQL 2:

WITH maxDates AS (SELECT hv.portfolio,
                                    hv.isin,
                                    YEAR(hv.price_date) as yr,
                                    MAX(hv.price_date) as maxDate
                            FROM holdings_VIEW_day_by_day hv
                            GROUP BY YEAR(hv.price_date), hv.portfolio, hv.isin),
        yrEndValues AS (SELECT md.*, hv.value
                                FROM holdings_VIEW_day_by_day hv
                                JOIN maxDates md ON md.portfolio = hv.portfolio AND md.isin = hv.isin AND md.maxDate = hv.price_date
                                GROUP BY hv.portfolio, hv.isin, YEAR(hv.price_date)
                                ORDER BY YEAR(hv.price_date), hv.stock_name)

SELECT hv.portfolio,
            hv.stock_name,
            CAST(YEAR(hv.price_date) AS CHAR) as yr,
            CONCAT(ROUND(100*(EXP(SUM(LN(hv.retrn_pct)))-1),1),"%") AS twRoR,
            ROUND(SUM(hv.retrn),0) AS retrn,
            ROUND(yEV.value,0) AS yrEndValue
    FROM holdings_VIEW_day_by_day hv
    LEFT JOIN yrEndValues yEV ON hv.portfolio = yEV.portfolio AND hv.isin = yEV.isin AND YEAR(hv.price_date) = yEV.yr
    GROUP BY hv.portfolio, hv.stock_name, YEAR(hv.price_date)
    ORDER BY YEAR(hv.price_date), hv.portfolio, hv.stock_name, EXP(SUM(LN(hv.retrn_pct))) DESC

联合 SQL:

WITH maxDates AS (SELECT hv1.portfolio,
                                    hv1.isin,
                                    YEAR(hv1.price_date) as yr,
                                    MAX(hv1.price_date) as maxDate
                            FROM holdings_VIEW_day_by_day hv1
                            GROUP BY YEAR(hv1.price_date), hv1.portfolio, hv1.isin),

        yrEndValues AS (SELECT md.*, hv.value
                                FROM holdings_VIEW_day_by_day hv
                                JOIN maxDates md ON md.portfolio = hv.portfolio AND md.isin = hv.isin AND md.maxDate = hv.price_date
                                GROUP BY hv.portfolio, hv.isin, YEAR(hv.price_date)
                                ORDER BY YEAR(hv.price_date), hv.stock_name),

        hv_sub AS (SELECT hv2.portfolio,
                                hv2.price_date,
                                SUM(hv2.VALUE) AS curValue,
                                SUM(hv2.VALUE) + IFNULL(SUM(tv.cashflow),0) AS netValue,
                                SUM(hv2.retrn) AS portfolio_retrn
                        FROM holdings_VIEW_day_by_day hv2
                            LEFT JOIN transactions_VIEW tv ON tv.tr_date = hv2.price_date AND hv2.portfolio = tv.portfolio AND hv2.isin = tv.isin
                        WHERE hv2.isin <> 'EU0000000000'
                        GROUP BY hv2.portfolio, hv2.price_date
                        ORDER BY hv2.price_date),

        portfolio_retrn_pct AS (SELECT hv_sub.portfolio,
                                                    hv_sub.price_date,
                                                    hv_sub.portfolio_retrn,
                                                    hv_sub.netValue / LAG(hv_sub.curValue,1) OVER (PARTITION BY hv_sub.portfolio ORDER BY hv_sub.price_date) AS portfolio_retrn_pct
                                            FROM hv_sub)


(SELECT hv.portfolio,
            hv.stock_name,
            CAST(YEAR(hv.price_date) AS CHAR) as yr,
            CONCAT(ROUND(100*(EXP(SUM(LN(hv.retrn_pct)))-1),1),"%") AS twRoR,
            ROUND(SUM(hv.retrn),0) AS retrn,
            ROUND(yEV.value,0) AS yrEndValue
    FROM holdings_VIEW_day_by_day hv
        LEFT JOIN yrEndValues yEV ON hv.portfolio = yEV.portfolio AND hv.isin = yEV.isin AND YEAR(hv.price_date) = yEV.yr
    GROUP BY hv.portfolio, hv.stock_name, YEAR(hv.price_date)
    ORDER BY YEAR(hv.price_date), hv.portfolio, hv.stock_name, EXP(SUM(LN(hv.retrn_pct))) DESC)

UNION

(SELECT prp.portfolio,
            '_Portfolio',
            CAST(YEAR(prp.price_date) AS CHAR) AS yr,
            CONCAT(ROUND(100*(EXP(SUM(LN(prp.portfolio_retrn_pct)))-1),1),"%") AS portfolio_twRoR,
            SUM(prp.portfolio_retrn) AS portfolio_retrn,
            0
    FROM portfolio_retrn_pct prp
    GROUP BY prp.portfolio, YEAR(prp.price_date))

ORDER BY yr, stock_name;

有人能指出我正确的方向吗?

进一步发现: 一旦我在最后删除全局 UNION SORT BY,警告就会消失。

(我也很乐意采取任何方式来优化这些查询......它看起来并不优雅,并且需要相当长的时间(15 秒)才能产生输出)

谢谢

【问题讨论】:

  • 添加一些示例表数据和预期结果 - 全部作为格式化文本,而不是图像。在开始之前考虑阅读stackoverflow.com/help/mcve
  • 我记得当我在第一组中有一个 (n)varchar 列时,SQL 决定它只有 n 个字符宽,但第二组中的同一列更宽时,我遇到了不合理的错误。不记得错误了……那是很久以前的事了……但我记得那是荒谬的。对于咯咯笑...尝试将两列显式转换为已知的大宽度...在第二列 (hv.stock_name) vs '_Portfolio'
  • 另外...看不出在联合之前的集合中有一个 order by 是有意义的...或任何与此相关的 with 子句。
  • 尝试投射前 2 列,但不幸的是没有成功。谢谢你的建议。我知道订单,只是在我开始工作之前没有费心把它们拿出来

标签: sql mariadb union


【解决方案1】:

问题可能是您的单个查询未处理整个结果集。所以他们在返回有问题的行之前返回行。

无论如何,使用nullif() 可以轻松避免除以零。因此,无论您有分区,都使用它。例如:

(hv_sub.netValue / 
 NULLIF(LAG(hv_sub.curValue, 1) OVER (PARTITION BY hv_sub.portfolio ORDER BY hv_sub.price_date), 0)
) AS portfolio_retrn_pct

【讨论】:

  • 谢谢戈登。我试图插入一个NULLIF,但实际上并没有避免错误,所以再次将其取出。
猜你喜欢
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-06
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2018-06-27
  • 1970-01-01
相关资源
最近更新 更多