加入两个查询会返回比预期更多的行?

Posted

技术标签:

【中文标题】加入两个查询会返回比预期更多的行?【英文标题】:Joining two queries returns much more rows than expected? 【发布时间】:2019-03-27 21:22:48 【问题描述】:

我有两个疑问。它们都返回大约 60 行。但加入它们后,它们返回 900 行。有没有办法在加入它们时获得 60 行。

查询 1:

SELECT 
    f.id_user,
    f.topup_date,
    f.topup_value,
    LEAD(f.topup_date) OVER (PARTITION BY(f.id_user) ORDER BY f.topup_date DESC),
    f.topup_date::timestamp - LEAD(f.topup_date::timestamp) OVER (PARTITION BY(f.id_user) ORDER BY f.topup_date DESC),
    CASE WHEN f.topup_value >= 20 THEN 'Y' ELSE 'N' end,
    CASE WHEN f.topup_value >= 20 THEN LEAD(f.topup_date) OVER (PARTITION BY (f.id_user) ORDER BY f.topup_date DESC) END
FROM topups AS f

查询 2:

SELECT 
    CAST(t2.topup_value as float)/CAST(t1.topup_value as float) 
FROM (
    SELECT 
        t1.id_user,
        t1.topup_value,
        ROW_NUMBER() OVER (PARTITION BY t1.id_user ORDER BY t1.topup_date ) AS rowrank
    FROM topups t1 
) AS t1 
INNER JOIN topups t2 ON t1.id_user=t2.id_user
WHERE t1.rowrank = 1
GROUP BY
    t2.id_user,
    t2.topup_value,
    t2.topup_date,
    t1.topup_value,
    t1.rowrank
ORDER BY 
    t2.id_user,
    t2.topup_date DESC

加入查询:

SELECT 
    f.id_user,
    f.topup_date,
    f.topup_value,
    LEAD(f.topup_date) OVER (PARTITION BY(f.id_user) ORDER BY f.topup_date DESC),
    f.topup_date::timestamp - LEAD(f.topup_date::timestamp) OVER (PARTITION BY(f.id_user) ORDER BY f.topup_date DESC),
    CASE WHEN f.topup_value >= 20 then 'Y' ELSE 'N' END,
    CASE WHEN f.topup_value >= 20 THEN LEAD(f.topup_date) OVER (PARTITION BY (f.id_user) ORDER BY f.topup_date desc) END,
    CAST(t2.topup_value AS float)/CAST(t1.topup_value AS float) 
FROM (
    SELECT 
        t1.id_user,
        t1.topup_value,
        ROW_NUMBER() OVER (PARTITION BY t1.id_user ORDER BY t1.topup_date ) AS rowrank
    FROM topups t1
) AS t1 
INNER JOIN topups t2 ON t1.id_user = t2.id_user 
INNER JOIN topups f  ON f.id_user = t2.id_user
WHERE t1.rowrank = 1
GROUP BY 
    f.id_user,
    f.topup_date,
    f.topup_value,
    t2.topup_value,
    t1.topup_value,
    t2.id_user,
    t2.topup_date
ORDER BY 
    t2.id_user,
    t2.topup_date DESC, 
    f.id_user,
    f.topup_date DESC

【问题讨论】:

你为什么只加入id_user?你不应该加入完整的topups 键吗?顺便说一句,您的第二个查询看起来很奇怪。 GROUP BY 子句有什么用?我看不到聚合(SUMCOUNT 等)。 我完全重新设计了您的 SQL 查询以使其可读。请考虑为您的下一个问题使用相同的格式规则!问题会很长且未格式化的 SQL 代码通常很少受到社区的关注... @GMB 非常感谢..下次我会记住的 @ThorstenKettner 我只是想加入这两个查询,所以我使用了 id_user。关于第二个查询,我需要根据每个用户 ID 以特定顺序输出某些列。我猜它没有真正的意义。我会删除它。 请在代码问题中给出minimal reproducible example--剪切&粘贴&可运行代码加上所需的输出加上清晰的规范和解释。最小意味着将最少的问题代码添加到最少的工作代码中。因此,给出你所展示的最少代码,并在你出错的第一个地方提供最少的代码。 (调试基础。)请通过编辑而不是 cmets 进行澄清。 PS你甚至没有解释或说明你想要什么结果。 “在加入时获得 60 行”尚不清楚。 “只是想加入这两个查询”告诉我们什么。准确告诉我们一行在结果中的含义。 【参考方案1】:

您想要连接两个查询结果。对于一个查询结果中的每一行,您希望在另一个查询结果中找到一行。因此,请查看第一个查询结果中的第一行。您似乎想将它与第二个查询结果中的一行完全连接起来。这是哪一排?为了找到匹配的行,您比较了哪些列?

假设这些是您的查询结果:

col1 | col4 | col7 | col6 | col3 -----+------+------+------+------ 一个 |乙| 100 | 110 |乙 一个 |乙| 19 | 22 |乙 F |克| 80 | 78 | H F |我 | 22 | 12 | Ĵ

col4 | col2 | col1 | col3 | col8 -----+------+------+------+------ 乙| 333 |一个 | E | 89 乙| 211 |一个 | E | 84 克| 815 | F | H | 77 我 |第639章F | Ĵ | 79

你想要这样的结果:

col1 | col4 | col7 | col6 | col3 | col4 | col2 | col1 | col3 | col8 -----+------+------+------+------+------+------+-- ----+------+----- 一个 |乙| 100 | 110 | E |乙| 333 |一个 | E | 89 一个 |乙| 19 | 22 | E |乙| 211 |一个 | E | 84 F |克| 80 | 78 | H |克| 815 | F | H | 77 F |我 | 22 | 12 | Ĵ |我 |第639章F | Ĵ | 79

但你得到的是这样的东西:

col1 | col4 | col7 | col6 | col3 | col4 | col2 | col1 | col3 | col8 -----+------+------+------+------+------+------+-- ----+------+----- 一个 |乙| 100 | 110 | E |乙| 333 |一个 | E | 89 一个 |乙| 100 | 110 | E |乙| 211 |一个 | E | 84 一个 |乙| 19 | 22 | E |乙| 333 |一个 | E | 89 一个 |乙| 19 | 22 | E |乙| 211 |一个 | E | 84 F |克| 80 | 78 | H |克| 815 | F | H | 77 F |克| 80 | 78 | Ĵ |我 |第639章F | Ĵ | 79 F |我 | 22 | 12 | H |克| 815 | F | H | 77 F |我 | 22 | 12 | Ĵ |我 |第639章F | Ĵ | 79

您得到了这样的结果,因为您刚刚选择了一列来连接两个查询结果(在您的情况下为id_user,在我的情况下为col1)。查看上面第一个查询结果的第一行。它有col1 = 'A'。如果我在col1 上加入第二个查询结果,则有两个匹配的行,因为第二个查询结果有两行与col1 = 'A'。我最终得到的比赛比我想要的要多。

那么,我们要匹配哪些列?在我的示例中,它是col1col3col4。再看第一个查询结果的第一行。它有col1 = 'A' and col3 = 'B' and col4 = 'E'。第二个结果集中只有一行匹配col1 = 'A' and col3 = 'B' and col4 = 'E'。因此我的查询是

select *
from (<query 1 here>) q1
join (<query 2 here>) q2 on q2.col1 = q1.col1 and q2.col3 = q1.col3 and q2.col4 = q1.col4;

或者我宁愿明确说明我想在结果中看到哪些列并删除重复的列:

select q1.col1, q2.col4, q1.col7, q1.col6, q1.col3, q2.col2, q2.col8
from (<query 1 here>) q1
join (<query 2 here>) q2 on q2.col1 = q1.col1 and q2.col3 = q1.col3 and q2.col4 = q1.col4
order by q1.col1, q2.col4, q1.col7;

【讨论】:

以上是关于加入两个查询会返回比预期更多的行?的主要内容,如果未能解决你的问题,请参考以下文章

查询中的 LEFT JOIN 返回比预期更多的记录

Oracle 过程分页带来比预期更多的行

左连接在查询后返回更多和更少的行

查询花费的时间比预期的要长

子查询处理比需要更多的行

Oracle SQL 选择不同的查询以返回特定的行数