在一个查询中两次从同一个表中提取时出现问题

Posted

技术标签:

【中文标题】在一个查询中两次从同一个表中提取时出现问题【英文标题】:Trouble pulling from the same table twice in one query 【发布时间】:2021-03-05 17:05:56 【问题描述】:

对不起,如果这个标题措辞奇怪。我正在处理一个查询,该查询会提取在某个地方拥有会员资格的人员列表。该查询从Demographics 表中提取一些人口统计信息,并从Visit 表中提取上次/下一次访问日期。即使某个人不再是会员,他们仍会保留在系统中,但他们的帐户会被标记为“已转移”标记(以 varchar 格式)。我需要能够在系统中提取 所有 成员的列表,但有一个列显示给定成员是否具有转移标志。标志字段也可以在Demographics 表中找到,并且成员可以拥有许多不同的标志。一个成员可能有 10 个不同的标志。

在我的脑海中,直接的解决方案是查询Demographics 表两次,第一个实例显示每个成员的实际人口统计数据,第二个实例显示转移的标志。查询运行没有错误;但是,它最终仍然显示转移的成员,我意识到我使用的逻辑不太合理。我认为我在正确的轨道上,但需要解决这个问题。

这是我的查询:

SELECT DISTINCT
    d.MemberID,
    d.MemberName,
    d.DateOfBirth,
    [a few other demographic fields blah blah],
    v.LastVisitDate,
    v.NextVisitDate,
    d2.MemberFlag as [Transferred?]

FROM Demographic d JOIN Visit v ON d.MemberID = v.MemberID
    JOIN Demographic d2 ON d.MemberID = d2.MemberID

WHERE d2.MemberFlag LIKE '%transf%'

我尝试了不同类型的JOINs,但没有任何效果,但就像我说的,我意识到我的逻辑有点不对劲。我觉得解决方案可能会变得非常简单,但我的大脑无法正常工作。这是我希望实现的目标:

MemberID   MemberName    ...    NextVisitDate    Transferred?
------------------------------------------------------------------
1001       John Smith    ...    03/10/2021
1002       Jane Doe      ...    NULL             Transferred
1003       Bob Brown     ...    04/22/2021
1004       Mike Jones    ...    03/17/2021
1005       Ann Green     ...    03/30/2021
1006       Dan White     ...    NULL             Transferred

★★更新★★

我找到了解决方案...我决定尝试在原始Demographics 表中仅使用带有标志字段的CASE,而不是再次尝试查询该表。

 SELECT DISTINCT
    d.MemberID,
    d.MemberName,
    d.DateOfBirth,
    [a few other demographic fields blah blah],
    v.LastVisitDate,
    v.NextVisitDate,
    (CASE
         WHEN d.MemberFlag LIKE '%transf%' THEN 'Transferred'
         ELSE ''
    END) AS [Transferred?]

FROM Demographic d JOIN Visit v ON d.MemberID = v.MemberID

几乎完美运行。我仍然遇到一个小问题,即任何拥有已转移标志的成员最终也会出现带有空白标志字段的行,所以就像那些人在重复一样。结果现在最终如下所示。关于如何避免这种情况的任何想法?

MemberID   MemberName    ...    NextVisitDate    Transferred?
------------------------------------------------------------------
1001       John Smith    ...    03/10/2021
1002       Jane Doe      ...    NULL             
1002       Jane Doe      ...    NULL             Transferred
1003       Bob Brown     ...    04/22/2021
1004       Mike Jones    ...    03/17/2021
1005       Ann Green     ...    03/30/2021
1006       Dan White     ...    NULL             
1006       Dan White     ...    NULL             Transferred

【问题讨论】:

提示:SELECT DISTINCT 通常是一种代码异味,因为这意味着您正在删除原本不应该重复的数据。那么,为什么你使用SELECT DISTINCT @Dai 老实说,这只是一种习惯,因为我必须使用的数据库结构很糟糕,如果我使用SELECT DISTINCT,一半的时间,我得到一堆重复的结果。但这与我要问的问题有什么关系吗? 好吧,你说你遇到了问题并且我看到你正在使用 select-distinct - 我认为它是相关的。 好吧,我刚刚删除了 DISTINCT 部分并再次对其进行了测试——这个简单的查询现在需要 几分钟 才能运行,而截至这一秒,还没有结束。暂时忽略这个问题,你还有其他想法吗?我原来的逻辑是否正确? 【参考方案1】:

我同意,您在人口统计表中的成员 ID、姓名和出生日期看起来像重复数据,每个数据表包含多行。不酷,但如果你有的话。

如果“MemberID”是唯一 ID,并且成员的姓名和出生日期在每一行都相同,那么您可以通过 memberID 应用一个组,然后在所有您想要的字段上执行 MAX()改变。例如:如果我的出生日期是 2000 年 3 月 5 日,并且我有 10 条记录,我的出生日期都是 2020 年 3 月 5 日,那么 MAX(d.DateOfBirth) 仍然会产生 3 月 5 日。所以考虑到这个前提,这个查询可能有助于获得您要查找的内容。

SELECT 
        d.MemberID,
        max( d.MemberName ) MemberName,
        max( d.DateOfBirth ) DateOfBirth,
        max( each other blah blah fields) blahField1,
        coalesce( max( v.LastVisitDate ), '' ) LastVisitDate,
        coalesce( max( v.NextVisitDate ), '' ) NextVisitDate,
        max( CASE WHEN d.MemberFlag LIKE '%transf%' THEN 'Transferred'
                 ELSE ''
            END) AS Transferred
    from
        Demographic d 
            JOIN Visit v 
                ON d.MemberID = v.MemberID
    group by
        d.MemberID

【讨论】:

【参考方案2】:

您可以使用 CTE 拉出转移的标志,然后左连接到它。

    with transferred as
        (
        select distinct MemberID, 'Y' as transfer_flag
        from demographic
        where MemberFlag like '%transf%'
        )
    select distinct
       d.MemberID, 
       d.MemberName,
       d.DateOfBirth, 
       v.LastVisitDate, 
       v.NextVisitDate, 
       t.transfer_flag
    from demographic d
    join visit v
      on v.MemberID = v.MemberID
    left join transferred t
      on t.MemberID = d.MemberID

在 sql-server 中,它可能看起来有点不同。我没有用过那个 dbms,但它可能看起来像这样......

    with transferred (MemberID, transfer_flag)
    as
        (
        select distinct MemberID, 'Y' 
        from demographic
        where MemberFlag like '%transf%'
        )
    select distinct
       d.MemberID, 
       d.MemberName,
       d.DateOfBirth, 
       v.LastVisitDate, 
       v.NextVisitDate, 
       t.transfer_flag
    from demographic d
    join visit v
      on v.MemberID = v.MemberID
    left join transferred t
      on t.MemberID = d.MemberID

【讨论】:

以上是关于在一个查询中两次从同一个表中提取时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

在php中两次调用相同的函数时出错

在同一个查询中两次使用 UNPIVOT

Spark:在查询中两次使用临时表?

在选择查询中两次调用用户定义的函数会导致效率低下吗?

在 Android > 6.0 中,第二次从图库中访问图像时出现安全权限异常

通过 JDBC 从 Spark 提取表数据时出现 PostgreSQL 错误