TSQL根据其他行的值计算行值

时间:2019-10-22 04:17:01

标签: sql-server tsql

我有一个名为WORDS的表,如下所示:

------------------------------
Symbol          ParentSymbol
------------------------------
a
ab
abc
abd
abda
abdb
b
ba
bb
bbbc
bbc
abcd
bbbbbbbbbbbbba

我想像这样更新ParentSymbol列:

------------------------------
Symbol          ParentSymbol
------------------------------
a
ab              a
abc             ab
abd             ab
abda            abd
abdb            abd
b
ba              b
bb              b
bbbc            bb
bbc             bb
abcd            abc
bbbbbbbbbbbbba  bb 
------------------------------

ParentSymbol列仅包含“符号列”中的值,如果未找到父项,则为null。

我正在考虑基于Symbol的子字符串进行分区的某种联接,但是我不知道如何。

有什么办法可以做到这一点?

3 个答案:

答案 0 :(得分:3)

ParentSymbol仅少一个字母吗?

UPDATE w
SET    ParentSymbol = left(Symbol, len(Symbol) - 1)
FROM   WORDS w

更新的查询

UPDATE  w
SET     ParentSymbol = ISNULL(p.ParentSymbol, '')
FROM    WORDS w
        OUTER APPLY
        (
            SELECT  TOP 1 ParentSymbol = x.Symbol
            FROM    WORDS  x
            WHERE   x.Symbol    <> w.Symbol
            AND     w.Symbol    LIKE x.Symbol + '%'
            ORDER BY x.Symbol DESC
         ) p

答案 1 :(得分:1)

以下代码首先找到与该值最接近的一个作为子字符串。

/*
create table #words (Symbol varchar(100), ParentSymbol varchar(100));
insert into #words (Symbol) values ('a')
insert into #words (Symbol) values ('ab')
insert into #words (Symbol) values ('abc')
insert into #words (Symbol) values ('abd')
insert into #words (Symbol) values ('abda')
insert into #words (Symbol) values ('abdb')
insert into #words (Symbol) values ('b')
insert into #words (Symbol) values ('ba')
insert into #words (Symbol) values ('bb')
insert into #words (Symbol) values ('bbbc')
insert into #words (Symbol) values ('bbc')
insert into #words (Symbol) values ('abcd')
*/

with cte as(
select w2.Symbol  as ChildSymbol,
        max(w.Symbol) as Symbol
from #words as w
    inner join #words as w2 ON w.Symbol <> w2.Symbol and charindex(w.Symbol,w2.Symbol) = 1
group by w2.Symbol
)
select w.Symbol,
        c.Symbol as ParentSymbol
from #words as w
    left outer join cte as c ON w.Symbol = c.ChildSymbol

答案 2 :(得分:0)

我尝试使用dense_rankrow_number窗口函数。

第二次尝试-

declare @table table (Symbol varchar(10));
insert into @table values 
('a')
,('ab')
,('abc')
,('abd')
,('abda')
,('abdb')
,('b')
,('ba')
,('bb')
,('bbbc')
,('bbc')
,('abcd');

;with cte as (
    select left(symbol, 1) as FirstSymbol
    from @table
    group by left(symbol, 1)
),
cte2 as (
    select *, ROW_NUMBER() over (partition by b.firstSymbol order by a.symbol) as RankInGroup
    from @table as a
    left join cte as b on left(a.Symbol, 1) = b.FirstSymbol
)
select a.Symbol as Symbol, b.Symbol as ParentSymbol
from cte2 as a
left join cte2 as b on a.FirstSymbol = b.FirstSymbol and a.RankInGroup = b.RankInGroup + 1;

第一次尝试-

declare @table table (Symbol varchar(10));
insert into @table values 
('a')
,('ab')
,('abc')
,('abd')
,('abda')
,('abdb')
,('b')
,('ba')
,('bb')
,('bbbc')
,('bbc')
,('abcd');
--select * from @table;

;with cte as (
    select
        symbol,
        dense_rank() over (
            order by (
                case
                    when symbol like 'a%' then 1 when symbol like 'b%' then 2 when symbol like 'c%' then 3 when symbol like 'd%' then 4
                    when symbol like 'e%' then 5 when symbol like 'f%' then 6 when symbol like 'g%' then 7 when symbol like 'h%' then 8
                    when symbol like 'i%' then 9 when symbol like 'j%' then 10 when symbol like 'k%' then 11 when symbol like 'l%' then 12
                    when symbol like 'm%' then 13 when symbol like 'n%' then 14 when symbol like 'o%' then 15 when symbol like 'p%' then 16
                    when symbol like 'q%' then 17 when symbol like 'r%' then 18 when symbol like 's%' then 19 when symbol like 't%' then 20
                    when symbol like 'u%' then 21 when symbol like 'v%' then 22 when symbol like 'w%' then 23 when symbol like 'x%' then 24
                    when symbol like 'y%' then 25 when symbol like 'z%' then 26
            end)
        ) as GroupNumber,
        row_number() over (
            partition by (
                case
                    when symbol like 'a%' then 1 when symbol like 'b%' then 2 when symbol like 'c%' then 3 when symbol like 'd%' then 4
                    when symbol like 'e%' then 5 when symbol like 'f%' then 6 when symbol like 'g%' then 7 when symbol like 'h%' then 8
                    when symbol like 'i%' then 9 when symbol like 'j%' then 10 when symbol like 'k%' then 11 when symbol like 'l%' then 12
                    when symbol like 'm%' then 13 when symbol like 'n%' then 14 when symbol like 'o%' then 15 when symbol like 'p%' then 16
                    when symbol like 'q%' then 17 when symbol like 'r%' then 18 when symbol like 's%' then 19 when symbol like 't%' then 20
                    when symbol like 'u%' then 21 when symbol like 'v%' then 22 when symbol like 'w%' then 23 when symbol like 'x%' then 24
                    when symbol like 'y%' then 25 when symbol like 'z%' then 26
            end) order by symbol
        ) as RankInGroup
    from @table
)
select a.Symbol as Symbol, b.Symbol as ParentSymbol
from cte a
left join cte b on a.GroupNumber = b.GroupNumber and a.RankInGroup = b.RankInGroup + 1;