【问题标题】:How to get a list of rows that have the same Id but different values in the same field如何获取同一字段中具有相同ID但值不同的行列表
【发布时间】:2015-09-07 10:43:46
【问题描述】:

我一直在玩关于重复的不同查询,但这并不是我真正需要的。我确实需要一个重复列表,但另一列中的值不同。

我正在尝试在 SQL Server 2012 中执行此操作。

我需要获取“重复”行的列表,其中 DocId 相同,但它们在表中具有不同的 PoId。

AuditId|DocMasterId|PoNumber
2224   |105        |11111
2374   |105        |11111
2574   |105        |11112
2624   |106        |232323
2874   |106        |242424

基于上述的查询应该返回

105 106

但理想情况下,如果我可以根据相同的 DocMasterId 列出每个不同 PO 的第一个和最后一个条目,那将是理想的解决方案,所以我最终会得到

AuditId|DocMasterId|PoNumber
2224   |105        |11111
2574   |105        |11112
2624   |106        |232323
2874   |106        |242424

关于如何在 SQL 中实现这一点的任何想法?

谢谢。

更新:

我应该澄清一下,我只想列出设置了 PONumber 的行,并且我希望我的结果按 DocMasterId 排序。

根据蒂姆的回答,最终结果如下:

WITH CTE AS
(
    SELECT AuditId, DocMasterId, PoNumber,
    RN_ASC  = ROW_NUMBER() OVER (PARTITION BY DocMasterID ORDER BY 
    PoNumber ASC),
    RN_DESC = ROW_NUMBER() OVER (PARTITION BY DocMasterID ORDER BY 
    PoNumber DESC),
    CNT = COUNT(*) OVER (PARTITION BY DocMasterID)
FROM dbo.MyTable
WHERE PONumber IS NOT NULL
)
SELECT AuditId, DocMasterId, PoNumber
FROM CTE
WHERE CNT >= 2
AND (RN_ASC = 1 OR RN_DESC = 1)
ORDER BY DocMasterId

【问题讨论】:

  • 你可以使用分组方式
  • “DocId 相同的地方.. 有不同的 PoId” 您没有显示这些列中的任何一个。 “如果我可以列出每个重复项的第一个和最后一个条目,那将是理想的解决方案” 指定 firstlast
  • 另外:您使用的是哪个 DBMS?后格雷斯?甲骨文?
  • 多个DocMasterId、PoNumber重复时如何选择AuditId? (2224 还是 2374?)
  • 嗨,对不起,我已经澄清了这个问题。我是 SQL Server 2012,理想情况下,我想获取同一 DocMasterId 下列出的每个条目的第一个 PO 编号和最后一个 PO 编号记录的列表。

标签: sql sql-server


【解决方案1】:
select AuditId, DocMasterId, PoNumber 
from ( select *,  ROW_NUMBER() OVER (PARTITION BY DocMasterId, PoNumber ORDER BY DocMasterId ASC) as a from tablename ) abc 
where a =1

我使用 DocMasterId 和 PoNumber 创建了一个分区列,它将为 DocMasterId、PoNumber 的每个相同值重复 Row_Number。然后我使用 where condition a=1

消除了重复记录

【讨论】:

  • 你能补充一些解释吗?
  • @AdrianCidAlmaguer 解释: 我使用DocMasterIdPoNumber 创建了一个分区列,这将对DocMasterId, PoNumber 的每个相同值重复Row_Number。然后我使用 where 条件 a=1 消除了重复记录
【解决方案2】:

这种方法使用排名函数和 CTE:

WITH CTE AS
(
    SELECT AuditId, DocMasterId, PoNumber,
      RN_ASC  = ROW_NUMBER() OVER (PARTITION BY DocMasterID ORDER BY PoNumber ASC),
      RN_DESC = ROW_NUMBER() OVER (PARTITION BY DocMasterID ORDER BY PoNumber DESC),
      CNT = COUNT(*) OVER (PARTITION BY DocMasterID)
    FROM dbo.TableName
)
SELECT AuditId, DocMasterId, PoNumber
FROM CTE
WHERE CNT >= 2
AND (RN_ASC = 1 OR RN_DESC = 1)
ORDER BY DocMasterId

Demo


根据您的 cmets 更新 PoNumber 中的 NULL 值应该被排除在 CNT 中,并且不计入 CNT

WITH CTE AS
(
    SELECT AuditId, DocMasterId, PoNumber,
      RN_ASC  = ROW_NUMBER() OVER (PARTITION BY DocMasterID 
                                   ORDER BY CASE WHEN PoNumber IS NULL THEN 1 ELSE 0 END ASC,
                                            PoNumber ASC),
      RN_DESC = ROW_NUMBER() OVER (PARTITION BY DocMasterID ORDER BY PoNumber DESC),
      CNT = SUM(CASE WHEN PoNumber IS NOT NULL THEN 1 END) OVER (PARTITION BY DocMasterID)
    FROM dbo.TableName
)
SELECT AuditId, DocMasterId, PoNumber
FROM CTE
WHERE CNT >= 2
AND (RN_ASC = 1 OR RN_DESC = 1)
ORDER BY DocMasterId

Demo 与您正确不返回任何记录的示例数据。

【讨论】:

  • 谢谢蒂姆!你太棒了!我不得不稍微修改一下查询,因为我忘了提到我的 PONumber 不是空的,它必须按 DocMasterId 排序,但是一旦改变,它就很有魅力!稍后我会发布我的更新查询。
  • 我们刚刚在实时数据库上运行了这个查询,返回的结果不正确。我们的一些 PONumber 为空,但似乎仍将它们作为更改值包含在内。知道我们如何从查询中排除这些吗?我认为我上面更新的查询可以解决问题,但事实并非如此。
  • @Thierry:您的查询似乎是正确的。不应该有PONumberNULL 的记录。您可以通过以下方式验证它:... SELECT * FROM CTE WHERE PONumber IS NULL,它不会产生任何记录。也许这些值是NULLvarchar 值)或者只是空的。
  • 你能试试这些值吗 (32101,823,NULL), (32102, 823,NULL), (59252, 823, 'PO201300057'), (1017082,823, 'PO201300057'), (1017084,823, 'PO201300057'), (1017090, 823,'PO201300057') 并将 PONumber 更改为 NVARCHAR(15)。当我们真的不应该得到任何东西时,这会返回一行。奇怪的是,我们创建了一个视图来排除所有为空的 PONumber 并针对该视图运行查询,它仍然返回 DocMasterId 823,以及许多其他属于这种情况的人!很奇怪!
  • @Thierry:我现在要回家了,但我仍然注意到问题。但也许它对你有帮助。
【解决方案3】:

只需GROUP BY?

select min(AuditId), DocMasterId, PoNumber
from tablename
group by DocMasterId, PoNumber

【讨论】:

    【解决方案4】:

    如果你的数据库支持窗口功能,那么试试这个

    ;WITH cte
         AS (SELECT Row_number()OVER(partition BY DocMasterId
                        ORDER BY AuditId DESC) a_rn,
                    Row_number()OVER(partition BY DocMasterId
                        ORDER BY AuditId )     d_rn,
                    *
             FROM   Yourtable)
    SELECT AuditId,
           DocMasterId,
           PoNumber
    FROM   cte
    WHERE  a_rn = 1 or D_rn =1
    

    【讨论】:

      猜你喜欢
      • 2018-10-05
      • 1970-01-01
      • 2018-08-09
      • 2017-04-23
      • 1970-01-01
      • 2017-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多