我无法正确表达问题以在线找到答案,所以我希望有人可以向我提供解决方案的链接,因为我认为这是一项相当常见的任务。
我们的产品种类繁多,想确定父母的身份。 所有产品名称均在同一列中,其逻辑如下
ProductId ProductName
-----------------------------------------------------------------------------
1 ABC
2 ABCD
3 ABCD1
4 ABCD2
结果应为
ABCD1和ABCD2 是 ABCD 的子代, ABCD 是 ABC
的子代ProductId ProductName ParentName ParentId
------------------------------------------------------------------------------
1 ABC NULL NULL
2 ABCD ABC 1
3 ABCD1 ABCD 2
...
答案 0 :(得分:3)
嗯。我认为这可以满足您的要求:
select p.*, pp.ProductName as parentName, pp.ProductId as parentId
from products p outer apply
(select top (1) pp.*
from products pp
where p.ProductName like pp.ProductName + '%' and
p.ProductId <> pp.ProductId
order by len(pp.ProductName) desc
) pp;
答案 1 :(得分:1)
If there's only 1 character difference.
Then you can LEFT JOIN to the ProductName & one wildcard character '_'
SELECT
p1.ProductId,
p1.ProductName,
p2.ProductName AS ParentName,
p2.ProductId AS ParentId
FROM Products p1
LEFT JOIN Products p2 ON p1.ProductName LIKE CONCAT(p2.ProductName,'_')
ORDER BY p1.ProductId;
Example snippet:
declare @Products table (
ProductId INT primary key identity(1,1),
ProductName varchar(30) not null,
unique (ProductName)
);
insert into @Products (ProductName) values
('ABC')
,('ABCD')
,('ABCD1')
,('ABCD2')
;
SELECT
p1.ProductId,
p1.ProductName,
p2.ProductName AS ParentName,
p2.ProductId AS ParentId
FROM @Products p1
LEFT JOIN @Products p2 ON p1.ProductName LIKE CONCAT(p2.ProductName,'_')
ORDER BY p1.ProductId;
Result:
ProductId ProductName ParentName ParentId
1 ABC NULL NULL
2 ABCD ABC 1
3 ABCD1 ABCD 2
4 ABCD2 ABCD 2
If it's possible that there's more than 1 character difference then:
SELECT TOP (1) WITH TIES
p1.ProductId,
p1.ProductName,
p2.ProductName AS ParentName,
p2.ProductId AS ParentId
FROM Products p1
LEFT JOIN Products p2 ON p1.ProductName LIKE CONCAT(p2.ProductName,'_%')
ORDER BY ROW_NUMBER() OVER (PARTITION BY p1.ProductId ORDER BY LEN(p2.ProductName) DESC);
答案 2 :(得分:1)
毫无疑问,戈登的答案在这里是最好的,但我仍然同意:
USE TEMPDB
CREATE TABLE #T (ProductID INT, ProductName VARCHAR (100))
INSERT INTO #T VALUES (1, 'ABC'), (2, 'ABCD'), (3, 'ABCD1'), (4, 'ABCD2')
WITH CTE AS
(
SELECT T.*,
T2.ProductID AS ParentID,
T2.ProductName AS ParentName
FROM #T AS T
CROSS JOIN #T AS T2
WHERE T.ProductName LIKE T2.ProductName + '%'
AND T.ProductID <> T2.ProductID
)
, CTE2 AS
(
SELECT TOP 1 T.*,
NULL AS ParentID,
NULL AS ParentName
FROM #T AS T
ORDER BY LEN (T.ProductName)
)
SELECT * FROM CTE UNION ALL SELECT * FROM CTE2 ORDER BY 1
答案 3 :(得分:0)
您尝试将Case与条件一起使用,并将每个条件表示为新列。您可以参考语法https://www.w3schools.com/sql/sql_case.asp
答案 4 :(得分:0)
You can use Common Table Expression (CTE) to do the job.
with product_table (ProductId, ProductName) as
(
select 1 ProductId , 'ABC' ProductName union all
select 2 ProductId , 'ABCD' ProductName union all
select 3 ProductId , 'ABCD1' ProductName union all
select 4 ProductId , 'ABCD2' ProductName --union all
)
,product_result (ProductId, ProductName, ParentName, ParentId) as
(
select ProductId, ProductName, convert(varchar,null) ParentName, convert(int, null) ParentId
from product_table
where ProductName = 'ABC' --start with
union all
select d.ProductId, d.ProductName, convert(varchar,p.ProductName) ParentName, p.ProductId ParentId
from product_table d
, product_result p
where d.ProductName like p.ProductName+'_'
)
select *
from product_result
The first part product_table must be replaced by your own product table. It is used here to generate a tempory dataset.
Your final query will look like:
with product_result (ProductId, ProductName, ParentName, ParentId) as
(
select ProductId, ProductName, convert(varchar,null) ParentName, convert(int, null) ParentId
from <YOUR_PRODUCT_TABLE_GOES_HERE>
where ProductName = 'ABC' --start with
union all
select d.ProductId, d.ProductName, convert(varchar,p.ProductName) ParentName, p.ProductId ParentId
from <YOUR_PRODUCT_TABLE_GOES_HERE> d
, product_result p
where d.ProductName like p.ProductName+'_'
)
select *
from product_result
CTE is available since SQL2008. for more info WITH common_table_expression (Transact-SQL)