【问题标题】:SQL: Need to remove duplicate rows in query containing multiple joinsSQL:需要删除包含多个连接的查询中的重复行
【发布时间】:2010-08-27 05:09:09
【问题描述】:

请注意,我是一个完整的 SQL 菜鸟,并且正在学习中。根据谷歌搜索(包括在此处搜索),我尝试使用 SELECT DISTINCT 和 GROUP BY 但两者都不起作用,可能是由于我所有的加入(如果有人知道他们为什么不能完全工作,那将有助于学习)。

我需要来自各种表格的数据,下面是我知道的唯一方法(我只知道基础知识)。下面的查询工作正常,但显示重复。我需要知道如何删除这些。我现在唯一的提示可能是嵌套的 SELECT 查询,但根据研究,我不确定如何实现它们。任何帮助都会很棒,谢谢!

USE SQL_Contest
go
SELECT
    CLT.Description AS ClockType,
    CLK.SerialNumber AS JobClockSerial,
    SIT.SiteNumber AS JobID,
    SIT.[Name] AS JobsiteName,
    SIT.Status AS SiteActivityStatus,
    DHA.IssuedDate AS DHAIssuedDate, -- Date the clock was assigned to THAT jobsite
    CLK.CreatedDate AS CLKCreatedDate, -- Date clock first was assigned to ANY jobsite
    SES.ClockVoltage
FROM tb_Clock CLK
INNER JOIN tb_ClockType CLT
ON CLK.TypeID = CLT.ClockTypeID
INNER JOIN tb_DeviceHolderActivity DHA
ON CLK.ClockGUID = DHA.DeviceGUID
INNER JOIN tb_Site SIT
ON SIT.SiteGUID = DHA.HolderGUID
LEFT JOIN tb_Session SES
ON SES.ClockSerialNumber = CLK.SerialNumber
WHERE DHA.ReturnedDate IS NULL
ORDER BY SIT.[Name] ASC

编辑:我将很快审查这些答案,非常感谢。我根据 Rob 的要求发布了额外的重复信息:

在我添加之前一切正常:

LEFT JOIN tb_Session SES
ON SES.ClockSerialNumber = CLK.SerialNumber

我需要的。那是出现重复的时候:

JobClock 2,500248E4,08-107,Brentwood Job,1,2007-05-04 13:36:54.000,2007-05-04 13:47:55.407,3049    
JobClock 2,500248E4,08-107,Brentwood Job,1,2007-05-04 13:36:54.000,2007-05-04 13:47:55.407,3049

我希望该信息只显示一次。本质上,此查询是确定所有已分配时钟的活动作业现场,并且该作业仅分配了一个时钟,并且它只是一个作业现场,但它出现了两次。

编辑 2:根据你们提供的帮助,我能够确定它们实际上不是重复的,并且每个会话都是独立的,这是唯一一个碰巧有两个会话的会话。因此,现在我将尝试弄清楚如何仅从最新会话中提取信息。

【问题讨论】:

  • 一些重复行的输出示例会很有帮助,因此我们可以看到 what's 被重复。答案几乎可以肯定涉及您未显示的列之一,在每个重复行中包含不同的值。
  • 我添加了应该有用的信息,谢谢 Rob!
  • 副本中是否有错字,因为DISTINCT 会删除它。作为“ses”上的 LEFT JOIN,我希望 ses.clockvoltage 为每一行显示不同的值。否则,这意味着您有多个相关的“ses”记录,并且需要查看您需要加入“ses”以消除重复项(如果可能)。
  • 如果您可以决定 如何 确定哪个是相关会话,您可以在我提供的示例中将其添加为子查询中的 WHERE 子句这应该会让你得到你想要的结果=)
  • 非常感谢罗伯!我试试看。

标签: sql


【解决方案1】:

如果在您添加之前一切都“正常”:

LEFT JOIN tb_Session SES
ON SES.ClockSerialNumber = CLK.SerialNumber

那么tb_Session中的每个CLK.SerialNumber必须有多个记录。

运行以下查询:

SELECT  *
FROM    tb_Session SES
WHERE   ClockSerialNumber = '08-107'

应该返回两条记录。您需要决定如何处理此问题(即您要使用哪条记录?),除非来自 tb_Session 的两行都包含相同的数据,在这种情况下,他们应该这样做吗?

您可以随时将查询更改为:

SELECT
    CLT.Description AS ClockType,
    CLK.SerialNumber AS JobClockSerial,
    SIT.SiteNumber AS JobID,
    SIT.[Name] AS JobsiteName,
    SIT.Status AS SiteActivityStatus,
    DHA.IssuedDate AS DHAIssuedDate, -- Date the clock was assigned to THAT jobsite
    CLK.CreatedDate AS CLKCreatedDate, -- Date clock first was assigned to ANY jobsite
    SES.ClockVoltage
FROM tb_Clock CLK
INNER JOIN tb_ClockType CLT
ON CLK.TypeID = CLT.ClockTypeID
INNER JOIN tb_DeviceHolderActivity DHA
ON CLK.ClockGUID = DHA.DeviceGUID
INNER JOIN tb_Site SIT
ON SIT.SiteGUID = DHA.HolderGUID
LEFT JOIN 
(
    SELECT DISTINCT ClockSerialNumber, ClockVoltage
    FROM tb_Session 
) SES
ON SES.ClockSerialNumber = CLK.SerialNumber
WHERE DHA.ReturnedDate IS NULL
ORDER BY SIT.[Name] ASC

因为这应该确保SES 对于ClockSerialNumberClockVoltage 的每个唯一组合只包含一条记录

【讨论】:

  • 我想这就是我的答案。根据会话发生的时间,它们都有不同的时间戳。知道如何告诉 SQL 按序列号仅提取最新会话吗?
  • 类似于:SELECT ClockSerialNumber, ClockVoltage FROM tb_Session S WHERE Timestamp = (SELECT MAX(Timestamp) FROM tb_Session S2 WHERE S.ClockSerialNumber = S2.ClockSerialNumber AND S.ClockVoltage = S2.ClockVoltage)
  • 谢谢 Rob,做到了!我仍在尝试通读它并找出确切的原因。 :)
  • @Shadow,很高兴能帮上忙 =) 试一试这个查询,在某些时候你会遇到“'我以前怎么不明白'的时刻”,然后它'一切都会变得清晰 =)
【解决方案2】:

以这个示例数据集为例:

成分

IngredientId IngredientName
============ =========
1            Apple
2            Orange
3            Pear
4            Tomato

食谱

RecipeId RecipeName
======== ==========
1        Apple Turnover
2        Apple Pie
3        Poached Pears

Recipe_Ingredient

RecipeId IngredientId Quantity
======== ============ ========
1        1            0.25
1        1            1.00
2        1            2.00
3        3            1.00

注意: 为什么 Apple Turnover 有两批苹果作为原料,不在这里也不在那里,它就是这样。

以下查询将为“Apple Turnover”食谱返回两行,为“Apple Pie”食谱返回一行,为“Poached Pears”食谱返回一行,因为有两个条目在成分 ID 1 的 Recipe_Ingredient 表中。这正是连接所发生的事情。

SELECT  I.IngredientName,
        R.RecipeName
FROM    Ingredient I
JOIN    Recipe_Ingredient RI
        ON I.IngredientId = RI.IngredientId
JOIN    Recipe R
        ON RI.recipeId = R.RecipeId

您可以通过将其更改为仅返回一行:

SELECT  I.IngredientName,
        R.RecipeName
FROM    Ingredient I
JOIN    Recipe_Ingredient RI
        ON I.IngredientId = RI.IngredientId
JOIN    Recipe R
        ON RI.recipeId = R.RecipeId
GROUP BY I.IngredientName, R.RecipeName

如果没有关于您的数据的更多细节,很难将其应用于您的特定场景,但演练可能会帮助您了解“重复”的来源,因为不熟悉 SQL 的人

【讨论】:

  • 我添加了其他信息。我很快就会对此进行审查。
【解决方案3】:

连接不是您的问题。从你的 cmets 我会推断你所说的“重复”不是实际的重复。如果从查询返回的 2 个“重复项”的所有列值都匹配,那么 SELECT DISTINCT 或 GROUP BY 肯定会消除它们。因此,您应该能够通过查看列定义来找到解决方案。

我最好的猜测是,由于日期的时间部分不匹配,您会得到同一日期的重复项,但实际上并不是重复项。要消除此问题,您可以仅使用此技术将日期字段截断为日期:

    DATEADD(DAY, DATEDIFF(DAY, 0, DHA.IssuedDate), 0) AS DHAIssuedDate,
    DATEADD(DAY, DATEDIFF(DAY, 0, CLK.CreatedDate), 0) AS CLKCreatedDate,   

如果这不起作用,您可能想看看JobClockSerial:此列是否属于查询结果?

【讨论】:

  • 我会试试的。如果我理解这个问题,我肯定需要结果中的序列号。它列在多个表中,我并不关心它来自哪个表,但我确实需要最终显示的序列号。
猜你喜欢
  • 1970-01-01
  • 2020-03-17
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多