寻找关于从哪个项目开始的一些指导,该项目可能以某种形式使用模式匹配。目前我有一个表格,其中包含一列类似于以下内容的属性标识号:
PropertyID| Property Name|
A001 Jefferson
A002 Madison
A002-01 Madison Outhouse
A002-02 James Madison Statue
A003 Franklin
A004 Jackson
A004-field2 Jackson Fields
... ...
A2001 Tubman
PropertyID字段是数据集的主键。连字符前面的字符串表示父属性,而连字符后面的值表示与父项相关联的子属性。我试图创建的是一个名为" Parent Property Name"这看起来如下:
PropertyID| Property Name| | Parent Property Name|
A001 Jefferson Jefferson
A002 Madison Madison
A002-01 Madison Outhouse Madison
A002-02 James Madison Statue Madison
A003 Franklin Franklin
A004 Jackson Jackson
A004-field2 Jackson Fields Jackson
... ...
A2001 Tubman Tubman
基本上我想要完成的是如果字符串在连字符之前是唯一的/没有连字符返回"属性名称" as" Parent Property Name",如果有连字符,则返回"属性名称"父级的值(即在连字符之前匹配不包含连字符的PropertyID。
任何关于如何处理这个问题的想法都将非常感激。
答案 0 :(得分:1)
我认为您可以使用join
:SQL Fiddle
select t.*, tparent.PropertyId
from t join
t tparent
on left(t.PropertyId, charindex('-', t.PropertyId + '-') - 1) = tparent.PropertyId;
您还可以使用first_value()
:SQL Fiddle
select t.*,
first_value(propertyId) over (partition by left(t.PropertyId, charindex('-', t.PropertyId + '-') - 1)
order by PropertyId) as parent_propertyid
from t;
答案 1 :(得分:0)
您可以使用subquery
:
select *,
(case when charindex ('-', ltrim(rtrim(PropertyID))) > 0
then (select top 1 t1.PropertyName
from table t1
where t1.PropertyID = left(t.PropertyId, charindex('-', t.PropertyId + '-') - 1)
) else PropertyName
end) as [Parent Property Name]
from table t;
答案 2 :(得分:0)
这应该是你应该做的事情:SQL Fiddle
with CTE as
(
select PropertyId
, PropertyName
, PropertyId ParentId
, PropertyName ParentName
, PropertyId AncestorId
, PropertyName AncestorName
from Property
where PropertyId not like '%-%'
union all
select b.PropertyId
, b.PropertyName
, a.PropertyId ParentId
, a.PropertyName ParentName
, a.AncestorId
, a.AncestorName
from CTE a
inner join Property b
on b.PropertyId like a.PropertyId + '-%'
and b.PropertyId not like a.PropertyId + '-%-%' --avoid having grandchildren too soon
)
select *
from CTE
order by PropertyId
第一个代码块获取所有根元素;即那些没有连字符的人。这些价值观是他们自己的父母&祖先。这些也是唯一将作为其他结果的祖先出现的值,因为它们处于最高级别。
select PropertyId
, PropertyName
, PropertyId ParentId
, PropertyName ParentName
, PropertyId AncestorId
, PropertyName AncestorName
from Property
where PropertyId not like '%-%'
然后我们使用递归位来捕获子元素。这将从表中的那些元素获取,其中PropertyId与表的现有记录'PropertyId相同,仅在末尾使用连字符和新值。我们排除那些在此之后有第二个连字符(或更多连字符)的字符串,以确保我们不会将小孙子列为小孩。
在同一个区块中,我们以不同的方式分配值;而不是Property,Parent和Ancestor接收相同的值,Property是当前属性,Parent是父记录的PropertyId,而Ancestor是Parent记录的祖先。
select b.PropertyId
, b.PropertyName
, a.PropertyId ParentId
, a.PropertyName ParentName
, a.AncestorId
, a.AncestorName
from CTE a
inner join Property b
on b.PropertyId like a.PropertyId + '-%'
and b.PropertyId not like a.PropertyId + '-%-%'
我想知道我对LIKE
的使用是否合适,或者CHARINDEX
等替代方案是否可能表现得更好。在调查中我发现this post表明CharIndex是最好的,但根据评论,其他人发现了不同的结果,并且自己运行这个我也看到了不同机器上的不一致行为。所以我怀疑这是一个容易过早优化的场景;即确保有效的方法;然后,如果您需要优化它,请测试环境中的优化,然后运行此代码以确保统计数据相关。
那就是说,如果你想测试/比较,这是一个使用CHARINDEX
的版本。这基于@GordonLinoff的解决方案。 SQL Fiddle
with CTE as
(
select PropertyId
, PropertyName
, PropertyId ParentId
, PropertyName ParentName
, PropertyId AncestorId
, PropertyName AncestorName
, 0 LastHyphenCharIndex
from Property
where charindex('-', PropertyId) = 0
union all
select b.PropertyId
, b.PropertyName
, a.PropertyId
, a.PropertyName
, a.AncestorId
, a.AncestorName
, charindex('-',b.PropertyId, a.LastHyphenCharIndex)
from CTE a
inner join Property b
--on left(b.PropertyId, charindex('-',b.PropertyId, a.LastHyphenCharIndex)) = a.PropertyId + '-'
on left(b.PropertyId, nullif(charindex('-',b.PropertyId, a.LastHyphenCharIndex),0)-1) = a.PropertyId
)
select *
from CTE
order by PropertyId
答案 3 :(得分:0)
这可以通过JOIN实现,如下所示: 我们在“ - ”符号之前提取PropertyID的Substring部分,并使用它连接回同一个表。如果一个记录没有“ - ”符号,则引出一个,这样子串部分总是返回一些东西,而CHARINDEX() - 1部分也不会为SUBSTRING函数返回负值以进行长度参数。
DECLARE @Temp AS TABLE ( PropertyID NVARCHAR(MAX), PropertyName NVARCHAR(MAX))
INSERT INTO @Temp ( PropertyID ,
PropertyName )
SELECT 'A001', 'Jefferson' UNION ALL
SELECT 'A002', 'Madison' UNION ALL
SELECT 'A002-01', 'Madison Outhouse' UNION ALL
SELECT 'A002-02', 'James Madison Statue' UNION ALL
SELECT 'A003', 'Franklin' UNION ALL
SELECT 'A004', 'Jackson' UNION ALL
SELECT 'A004-field2', 'Jackson Fields' UNION ALL
SELECT 'A2001', 'Tubman'
SELECT *, CHARINDEX('-',T1.PropertyID)
FROM @Temp T1 LEFT JOIN @Temp T2
ON SUBSTRING(T1.PropertyID,1,CHARINDEX('-',T1.PropertyID+'-')-1) = T2.PropertyID