Sql 如何在同一字段中获取Id相同但值不同的行列表
我一直在处理关于重复项的不同查询,但这并不是我真正需要的。我确实需要一个重复列表,但另一列中的值不同 我正试图在SQLServer2012中实现这一点 我需要得到一个“重复”行列表,其中DocId相同,但表中的PoId不同Sql 如何在同一字段中获取Id相同但值不同的行列表,sql,sql-server,Sql,Sql Server,我一直在处理关于重复项的不同查询,但这并不是我真正需要的。我确实需要一个重复列表,但另一列中的值不同 我正试图在SQLServer2012中实现这一点 我需要得到一个“重复”行列表,其中DocId相同,但表中的PoId不同 AuditId|DocMasterId|PoNumber 2224 |105 |11111 2374 |105 |11111 2574 |105 |11112 2624 |106 |232323 2874
AuditId|DocMasterId|PoNumber
2224 |105 |11111
2374 |105 |11111
2574 |105 |11112
2624 |106 |232323
2874 |106 |242424
基于上述内容的查询应返回
105
106
但理想的情况是,如果我能根据相同的DocMasterId列出每个不同采购订单的第一个和最后一个条目,这将是理想的解决方案,因此我最终会
AuditId|DocMasterId|PoNumber
2224 |105 |11111
2574 |105 |11112
2624 |106 |232323
2874 |106 |242424
关于如何在SQL中实现这一点,有什么想法吗
谢谢
更新:
我应该澄清一下,我只想列出具有PONumber集合的行,并且我希望我的结果按DocMasterId排序
根据Tim的回答,最终结果如下:
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
如果您的数据库支持窗口功能,请尝试以下操作
;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
该方法使用排序函数和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
根据您的评论进行更新,
PoNumber
中的NULL
值应排除在外,且不计入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
您的样本数据不会正确返回任何记录。简单地
分组依据
select min(AuditId), DocMasterId, PoNumber
from tablename
group by DocMasterId, PoNumber
我使用DocMasterId和PoNumber创建了一个分区列,它将为DocMasterId的每个相同值PoNumber重复行号。然后我使用where条件a=1消除了重复记录您可以使用Group by“where the DocId is same..have a different PoId”您没有显示任何这些列。“如果我能列出每个副本的第一个和最后一个条目,那将是理想的解决方案”指定第一个和最后一个。另外:您使用的是哪种DBMS?博士后?Oracle?如果多个DocMasterId、PoNumber重复,如何选择试镜?(2224或2374?)嗨,对不起,我已经澄清了这个问题。我是SQL Server 2012,理想情况下,我希望获得在同一DocMasterId下列出的每个条目的第一个PO编号和最后一个PO编号记录的列表。谢谢Tim!你太棒了!我不得不稍微修改一下查询,因为我忘了提到我的PONumber不是空的,它必须按DocMasterId排序,但一旦更改,它就起了作用!!我马上发布我的更新查询。我们刚刚在一个实时数据库上运行了此查询,返回的结果不正确。我们的一些PONUMBER是空的,但它似乎仍然将它们作为已更改的值包含在内。知道我们如何从查询中排除这些吗?我原以为我在上面更新的查询会成功,但事实并非如此。@Thierry:您的查询似乎是正确的。如果PONumber
为NULL
,则不应存在任何记录。您可以通过以下方式进行验证:。。。从CTE中选择*,其中PONumber为空
,不产生任何记录。这些值可能是NULL
(varchar
值)或只是空的。请尝试这些值(32101823,NULL),(32102823,NULL),(59252823,'PO201300057'),(1017082823,'PO201300057'),(1017084823,'PO201300057'),(1017090823,'PO201300057'),并将PONumber更改为NVARCHAR(15)。这将返回一行,而我们实际上应该什么都没有。奇怪的是,我们创建了一个视图来排除所有为null的PONumber,并对该视图运行了查询,它仍然返回DocMasterId 823,以及其他许多属于这种情况的PONumber!非常奇怪@蒂埃里:我现在要回家了,但我还是注意到了一些问题。但也许它对你有帮助。你可以添加一些解释吗?@AdrianCidAlmaguer解释:我使用DocMasterId
和PoNumber
创建了一个分区列,它将对DocMasterId,PoNumber
的每个相同值重复行号。然后我使用where条件a=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