为啥 MySQL View 和同一个 View 的底层 SELECT 查询返回不同的结果?

Posted

技术标签:

【中文标题】为啥 MySQL View 和同一个 View 的底层 SELECT 查询返回不同的结果?【英文标题】:Why does MySQL View and the same View's underlying SELECT query return different results?为什么 MySQL View 和同一个 View 的底层 SELECT 查询返回不同的结果? 【发布时间】:2020-01-17 11:58:10 【问题描述】:

我可以在这里得到一些帮助来解决这个问题,我正在尝试生成一组结果,其中包含结转余额和结转余额。

mysql 脚本:

CREATE OR REPLACE VIEW vwbalances AS
SELECT th.user_id usrid
     , YEAR(th.date_created) year 
     , IFNULL(
              (SELECT SUM(tx.amount) 
                 FROM transdetail tx 
                 JOIN transhdr th 
                   ON th.thdr_id = tx.thdr_id
                 JOIN users u 
                   ON th.user_id = u.user_id 
                 JOIN transtype tt 
                   ON tt.ttype_id = tx.ttype_id 
                WHERE tx.ttype_id in (2,9,11) 
                  AND u.user_id = usrid 
                  and YEAR(tx.date_created) < year
              )
           ,0) bal_bfwd
     , SUM(td.amount) bal_ytd
     , ifnull(
              (SELECT SUM(ty.amount) 
                 FROM transdetail ty 
                 JOIN transhdr th
                   ON th.thdr_id = ty.thdr_id
                 JOIN users u 
                   ON th.user_id = u.user_id 
                 JOIN transtype tt 
                   ON tt.ttype_id = ty.ttype_id 
                WHERE ty.ttype_id in (2,9,11) 
                  AND u.user_id = usrid 
                  AND YEAR(ty.date_created) <= year
              )
           ,0) bal_cfwd
  FROM transdetail td 
  JOIN transhdr th 
    ON th.thdr_id = td.thdr_id
  JOIN users u 
    ON th.user_id = u.user_id 
  JOIN transtype tt 
    ON tt.ttype_id = td.ttype_id 
 WHERE td.ttype_id in (2,9,11) 
 GROUP 
    BY th.user_id
     , YEAR(th.date_created)

我在运行 SELECT * FROM vwbalances 时得到这个(不正确的结果):

当我运行用于创建 VIEW 的完整 SELECT 语句时,我得到了这个(正确的结果):

提前致谢。

【问题讨论】:

【参考方案1】:

您发布的查询甚至不应该工作。

usrid 是您最外层选择中的别名。它在您的子查询中不可用。 除非您有一个名为 year 的列,否则 year(tx.date_created) &lt; year 之类的内容也不应该工作 在外部查询和子查询中使用相同的表别名。这也不应该是可能的。如果是,这可能就是您得到奇怪结果的原因。

除此之外,您不必多次执行基本相同的查询。您可以将查询缩短为如下所示:

SELECT `th`.`user_id` AS usrid
    , year(`th`.`date_created`) AS 'year'
sum(if(year(td.date_created`) < year, amount, 0)) as bal_ytd,
sum(if(year(td.date_created`) <= year, amount, 0)) as bal_cfwd
FROM `transdetail` `td`
JOIN `transhdr` `th` ON `th`.`thdr_id` = `td`.`thdr_id`
JOIN `users` `u` ON `th`.`user_id` = `u`.`user_id`
JOIN `transtype` `tt` ON `tt`.`ttype_id` = `td`.`ttype_id`
WHERE `td`.`ttype_id` IN (2, 9, 11)
GROUP BY `th`.`user_id`
    , year(`th`.`date_created`)

(当然,这个奇怪的 year 对你有用)

【讨论】:

感谢您的意见。带着这些,我仍然在努力用正确的数字显示 2 列(向前和向前推进)。基本上对于 2016 年的每一行,我想在 bfwd 列中看到 cfwd 列中的 2015 年数字。这就是为什么我在这些列中有子查询。任何替代方法?【参考方案2】:

以下脚本运行正常。感谢所有帮助和提示:

CREATE OR REPLACE VIEW vwbalances AS
SELECT tho.user_id AS usrid, YEAR(td.date_created) AS 'year' 

, ROUND(IFNULL((SELECT sum(tx.amount) FROM transdetail tx 
JOIN transhdr th ON th.thdr_id = tx.thdr_id
JOIN users u ON th.user_id = u.user_id 
JOIN transtype tt ON tt.ttype_id = tx.ttype_id 
WHERE tx.ttype_id IN (2,9,11) AND u.user_id = tho.user_id AND 
YEAR(tx.date_created) < YEAR(td.date_created) ),0),2) AS 
bal_bfwd

, round(sum(td.amount),2) AS bal_ytd

, ROUND(IFNULL((select SUM(ty.amount) FROM transdetail ty 
JOIN transhdr th on th.thdr_id = ty.thdr_id
JOIN users u ON th.user_id = u.user_id 
JOIN transtype tt ON tt.ttype_id = ty.ttype_id 
WHERE ty.ttype_id IN (2,9,11) AND u.user_id = tho.user_id AND 
YEAR(ty.date_created) <= YEAR(td.date_created)),0),2) AS 
bal_cfwd

FROM transdetail td JOIN transhdr tho ON tho.thdr_id = 
td.thdr_id
JOIN users u ON tho.user_id = u.user_id 
JOIN transtype tt on tt.ttype_id = td.ttype_id 
WHERE td.ttype_id IN (2,9,11) 
GROUP BY tho.user_id, YEAR(td.date_created);

【讨论】:

以上是关于为啥 MySQL View 和同一个 View 的底层 SELECT 查询返回不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 View 是 utf8 以及如何将其更改为 latin1

为啥navigationBar和view之间显示黑屏

为啥来自 VIEW 的 SELECT * 比来自同一个 VIEW 的 SELECT(特定列)执行得更快?

为啥loadview中的self.view.tag和其他的不一样

为啥我在 View SELECT 查询中收到带有 WHERE 子句的“未知列 'xyz'”?

为啥 self.view 的高度和宽度与子视图的高度和宽度不同?