UNION结果集部分与单个SELECT不同

时间:2017-03-16 00:16:17

标签: mysql union mariadb union-all

查询

(SELECT timest, `char`, exp_cnt AS XP FROM `charac` WHERE DATE(timest)='2017-01-30')
UNION
(SELECT timest, `char`, -exp_cnt AS XP FROM `charac` WHERE DATE(timest)=ADDDATE('2017-01-30',-1))
ORDER BY `char` ASC
LIMIT 50

给我这个结果:
UNION querry

如果日期为01-29,则值通常不应为0 我尝试通过复制粘贴并运行第二个SELECT

来调试它
SELECT timest, `char`, -exp_cnt AS XP FROM `charac` WHERE DATE(timest)=ADDDATE('2017-01-30',-1)  
ORDER BY `char` ASC

我得到了正确的结果!
individual mysql select

为什么呢?我很迷惑。 UNION ALL无效。

2 个答案:

答案 0 :(得分:1)

首先,您应该使用union all而不是union,除非您想要承担删除重复项的开销。

其次,您在查询中有limit。因此,您的结果可能正在生成,它们只是在列表的下方并截止。

如果您关心2017-01-29发生的事情,请按日期对列表进行排序并按比例进行比较:

(SELECT timest, `char`, exp_cnt AS XP
 FROM `charac`
 WHERE DATE(timest) = '2017-01-30'
) UNION ALL
(SELECT timest, `char`, -exp_cnt AS XP
 FROM `charac`
 WHERE DATE(timest) = ADDDATE('2017-01-30', -1)
)
ORDER BY timest ASC
LIMIT 50;

这可能不是您想要的最终结果,但您至少会看到所有行都被计算在内。

如果您在29日不想要0值,那么请将其明确地放入查询中:

(SELECT timest, `char`, exp_cnt AS XP
 FROM `charac`
 WHERE DATE(timest) = '2017-01-30'
) UNION ALL
(SELECT timest, `char`, -exp_cnt AS XP
 FROM `charac`
 WHERE DATE(timest) = ADDDATE('2017-01-30', -1) AND
       exp_cnt <> 0
)
ORDER BY timest ASC
LIMIT 50;

答案 1 :(得分:1)

每天有多少行?我敢打赌,30日不到50。我敢打赌UNION获得了30日的所有行,然后是29日的所有行。这可以解释它。

要进一步测试我的理论,请分别运行SELECT中的每个UNION

另一项测试:交换SELECTs中的两个UNION。现在它可能会丢失30日的部分行。

如果您想要两者中的前50个,请使用以下模式:

( SELECT ... ORDER BY timest LIMIT 50 )
UNION ALL
( SELECT ... ORDER BY timest LIMIT 50 )
ORDER BY timest LIMIT 50

如果您还需要OFFSET,它会变得更加混乱,但是可能:

比方说,第3页:

  • 在里面,做LIMIT 150 - 确保每个至少150(如果有的话)
  • 外面,LIMIT 100, 50 - 在<{em> ORDER BY
  • 之后只获取第3页

但......还有另一个问题。由于timest不是唯一的,因此挑选的50不是确定性的。因此,您可能希望更改为ORDER BY timest, idORDER BY timest, char