模式匹配在sql中创建一个新列?

时间:2018-05-31 15:24:51

标签: sql sql-server

寻找关于从哪个项目开始的一些指导,该项目可能以某种形式使用模式匹配。目前我有一个表格,其中包含一列类似于以下内容的属性标识号:

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。

任何关于如何处理这个问题的想法都将非常感激。

4 个答案:

答案 0 :(得分:1)

我认为您可以使用joinSQL 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