Sta*_*vas 7 sql t-sql sql-server group-by sql-server-2008
交代
想象一下,这里有3家公司.我们正在加入表格Name,因为不是每个员工都提供了他的PersonalNo.StringId只有专家,所以也不能用于加盟.同一名员工可以在多家公司工作.
问题
问题是可能存在具有相同名称的不同员工(具有相同的名字和姓氏,在示例中仅提供名字).
我需要的?
1数据有问题时返回,0如果正确.
检测问题的规则
PersonalNo而不是所有人都有StringId(如彼得)应该返回1(这是错误的)NULL(见约翰),但它们都有相同StringId它应该返回0(这是正确的,这意味着没有提供的公司之一PersonalNo)PersonalNo都是相同的并且都是相同的StringId(参见Lisa)它应该返回0(正确)PersonalNo而且全部StringId提供它应该是这样的:我们看到这里有两个不同的人Jennifer 4805250141 PersonalNo和Jennifer一起4920225088 PersonalNo,Jennifer 和Jennifer NULL PersonalNo一样StringId有4920225088 PersonalNo它应该返回0(正确的)和詹妮弗与4805250141 PersonalNo不宜选用,因为有StringID和只有1行具有相同的PersonalNo.StringId它应该不会出现在选择中.样本数据
Company Name PersonalNo StringId
Comp1 Peter 3850342515 85426 -------------------------------------------------------------------
Comp2 Peter 3850342515 '' -- If have the same PersonalNo and there is no StringId - 1 (wrong)
Comp1 John NULL 12345 ------------------------------------------------------------------
Comp2 John 3952525252 12345 -- If have the same StringId and 1 PersonalNo is NULL - 0 (correct)
Comp1 Lisa 4951212581 52124 ----------------------------------------------------------------
Comp3 Lisa 4951212581 52124 -- If PersonalNo are equal and StringId are equal - 0 (correct)
Comp1 Jennifer 4805250141 '' -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Comp1 Jennifer 4920225088 55443 -- If have 2 different PersonalNo and NULL PersonalNo, but where PersonalNo is NULL
Comp3 Jennifer NULL 55443 -- Have the same StringId with other row where is provided PersonalNo it should be 0 (correct), with different PersonalNo where is no StringId shouldn't appear at all.
Comp1 Ralph 3961212256 '' -- Shouldn't appear in select list, because only 1 row with this PersonalNo and there is no StringID
Run Code Online (Sandbox Code Playgroud)
期望的输出
Peter 1
John 0
Lisa 0
Jennifer 0
Run Code Online (Sandbox Code Playgroud)
QUERY
LEFT JOIN (SELECT Name,
(
SELECT CASE WHEN MIN(PersonalNo) <> MAX(d.PersonalNo)
and MIN(CASE WHEN StringId IS NULL THEN '0' ELSE StringId END) <> MAX(CASE WHEN d.StringId IS NULL THEN '0' ELSE d.StringId END) -- this is wrong
and MIN(PersonalNo) <> ''
and MIN(PersonalNo) IS NOT NULL
and MAX(rn) > 1 THEN 1
ELSE 0
END AS CheckPersonalNo
FROM (
SELECT Name, PersonalNo, [StringId], ROW_NUMBER() OVER (PARTITION BY Name, PersonalNo ORDER BY Name) rn
FROM TableEmp e1
WHERE Condition = 1 and e1.Name = d.Name
) sub2
GROUP BY Name
) CheckPersonalNo
FROM [TableEmp] d
WHERE Condition = 1
GROUP BY Name
) f ON f.Name = x.Name
Run Code Online (Sandbox Code Playgroud)
查询的问题是我只能分组Name,不能添加PersonalNo到GROUP BY子句,所以我需要在选择列表中使用聚合.但是现在只比较MIN和MAX值,如果有超过2行具有相同的名称它没有按预期工作.
我需要做一些比较,比较值PARTITION BY Fullname, PersonalNo.它现在比较相同的值Name(不依赖于PersonalNo).
有任何想法吗?如果您有任何问题 - 请问我,我会尽力解释.
更新1
如果有2个条目有不同PersonalNo,但它们StringId相等,那应该是1(错误的).
Company Name PersonalNo StringId
Comp1 Anna 4805250141 88552 -- different PersonalNo and the same StringId for both should go as 1 (wrong)
Comp1 Anna 4920225088 88552
Run Code Online (Sandbox Code Playgroud)
现在回来像:
Anna 0
Anna 0
Run Code Online (Sandbox Code Playgroud)
它应该是:
Anna 1
Run Code Online (Sandbox Code Playgroud)
更新2
UNION在Identifier列返回更新后StringId: 55443(对于下面的数据),但在这种情况下,当1个条目有PersonalNo,其他是blank,但它们都有相同(相等)StringId它是正确的(应该是0)
Comp1 Jennifer 4920225088 55443
Comp3 Jennifer '' 55443
Run Code Online (Sandbox Code Playgroud)
小智 2
我希望我已经理解你的要求..
也许还有其他方法可以做到这一点,但就我个人而言,如果是我这样做,我可能会使用临时表进行临时工作。
--select data into a temp table that can be modified
select
*
into #cleaned
from
table
--apply personal numbers based on other records with matching string id
--you could take note of the records you are doing this to for data clean up
update c
set c.personalNo = s.personalNo
from #cleaned as c
inner join table as s
on c.name = s.name
and c.stringID = s.stringID
and c.personalNo is null
and s.personalNo is not null
--find all records with non matching string ids
select
name
,PersonalNo
,count(*) as numIDs
into #issues
from(
select
name
,PersonalNo
,stringID
from
#cleaned
group by
name
,PersonalNo
,stringID
) as i
group by
name
,PersonalNo
having
count(*) > 1
--select data for viewing.
select
distinct
s.name
,case
when i.name is not null then 1
else 0
end as issue
from
#cleaned as s
left outer join #issues as i
on s.name = i.name
and s.personalNo = i.personalNo
order by issue desc
Run Code Online (Sandbox Code Playgroud)
SQLFiddle: http: //sqlfiddle.com/#!3/f4aab /7
抱歉,如果这里有错误,但我相信你会明白的,这不是火箭科学,只是另一种方法
编辑:刚刚注意到您对没有字符串 ID 的行感兴趣..如果它是唯一的行那么这不是问题。我修改了第一个选择(进入#cleaned)以获取所有行。
编辑:没有临时表现在您知道它在做什么,这里是相同的事情,没有任何临时表 - 但警告这会更新源表以分配丢失的个人编号
update c
set c.personalNo = s.personalNo
from table1 as c
inner join table1 as s
on c.name = s.name
and c.stringID = s.stringID
and c.personalNo is null
and s.personalNo is not null
select
distinct
s.name
,case
when i.name is not null then 1
else 0
end as issue
from
table1 as s
left outer join (
select
name
,PersonalNo
,count(*) as numIDs
from(
select
name
,PersonalNo
,stringID
from
table1
group by
name
,PersonalNo
,stringID
) as i
group by
name
,PersonalNo
having
count(*) > 1
)
as i
on s.name = i.name
and s.personalNo = i.personalNo
order by issue desc
Run Code Online (Sandbox Code Playgroud)
SQLFiddle: http: //sqlfiddle.com/#!3/f4aab /8
分区我不知道如何在这里使用分区,因为您想要做的只是知道是否有不止一行,我使用来自更复杂的表格的分区,或者我是否要对更新数据的判断调用的结果进行排名基于更复杂的规则..但无论如何,这里都是被禁止分区的乌鸦:D
Select
name
,personalNo
,case
when numstrings > 1 then 1
else 0 end as issue
from
(select
name
,personalNo
,row_number() over (partition by
name
,personalNo
order by
name
,personalNo
,stringID
) as numstrings
from
#cleaned
group by
name
,personalNo
,stringid) as d
order by
issue desc
Run Code Online (Sandbox Code Playgroud)
注意:这使用了上面的#cleaned表,因为我相信这很难的关键是有时缺少personalNo。
没有临时表,没有更新
使用上面的方法显然可以在没有任何临时表或更新任何内容的情况下完成,这只是可读性/可维护性以及它是否实际上更快的问题。这可以更稳定地处理分配了多个personalNo的字符串id:
select
distinct
s.name
,case
when i.name is not null then 1
else 0
end as issue
from
table1 as s
left outer join (
select
name
,PersonalNo
,count(*) as numIDs
from(
select
a.name
,coalesce(a.PersonalNo,b.PersonalNo) as PersonalNo
,a.stringID
from
table1 as a
left outer join table1 as b
on a.name = b.name
and a.stringid=b.stringid
and a.personalNo != b.personalNo
and b.personalNo Is Not Null
group by
a.name
,a.PersonalNo
,a.stringID
,b.PersonalNo
) as i
group by
name
,PersonalNo
having
count(*) > 1
)
as i
on s.name = i.name
and s.personalNo = i.personalNo
order by issue desc
Run Code Online (Sandbox Code Playgroud)
SQLFiddle: http: //sqlfiddle.com/#!3/f4aab /9
编辑:也寻找不一致的个人号码- 这使用一个临时表,但您可以像上一个示例中那样交换它。注意,与您要求的原始结构略有偏差,因为这更多是我会这样做的方式任务,但这里有足够的代码供您以任何您想要的方式重新调整。
--select data into a temp table that can be modified
select
*
into #cleaned
from
table1
--apply personal numbers based on other records with matching string id
--you could take note of the records you are doing this to for data clean up
update c
set c.personalNo = s.personalNo
from #cleaned as c
inner join table1 as s
on c.name = s.name
and c.stringID = s.stringID
and c.personalNo is null
and s.personalNo is not null
Select
IssueType
,Name
,Identifier
from
(
--find all records with non matching PersonalNos
select
name
,cast('StringID: ' + stringID as nvarchar(400)) as Identifier
,cast('Inconsistent PersonalNo' as nvarchar(400)) as issueType
from(
select
name
,PersonalNo
,stringID
from
#cleaned
group by
name
,PersonalNo
,stringID
) as i
group by
name
,StringId
having
count(*) > 1
UNION
--find all records with non matching string ids
select
name
,'PersonalNo: ' + PersonalNo
,cast('Inconsistent String ID' as nvarchar(400)) as issueType
from(
select
name
,PersonalNo
,stringID
from
#cleaned
group by
name
,PersonalNo
,stringID
) as i
group by
name
,PersonalNo
having
count(*) > 1
) as a
Run Code Online (Sandbox Code Playgroud)
SQLFiddle: http: //sqlfiddle.com/#!3/ e9da2/18
更新:也想接受空字符串personalNo's 这是另一个新要求..以与personalNo中的NULL相同的方式接受空字符串
--select data into a temp table that can be modified
select
*
into #cleaned
from
table1
--apply personal numbers based on other records with matching string id
--you could take note of the records you are doing this to for data clean up
update c
set c.personalNo = s.personalNo
from #cleaned as c
inner join table1 as s
on c.name = s.name
and c.stringID = s.stringID
and (c.personalNo IS NULL OR c.personalNo ='')
and s.personalNo is not null
and s.personalNo != ''
Select
IssueType
,Name
,Identifier
from
(
--find all records with non matching PersonalNos
select
name
,cast('StringID: ' + stringID as nvarchar(400)) as Identifier
,cast('Inconsistent PersonalNo' as nvarchar(400)) as issueType
from(
select
name
,PersonalNo
,stringID
from
#cleaned
group by
name
,PersonalNo
,stringID
) as i
group by
name
,StringId
having
count(*) > 1
UNION
--find all records with non matching string ids
select
name
,'PersonalNo: ' + PersonalNo
,cast('Inconsistent String ID' as nvarchar(400)) as issueType
from(
select
name
,PersonalNo
,stringID
from
#cleaned
group by
name
,PersonalNo
,stringID
) as i
group by
name
,PersonalNo
having
count(*) > 1
) as a
Run Code Online (Sandbox Code Playgroud)
SQLFiddle: http: //sqlfiddle.com/#!3/412127/8