SQL LEFT JOIN 到许多类别
SQL LEFT JOIN to many categories
假设以下简单 scenario,其中产品行连接到一个主要类别、子类别和子类别。
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1', '10', '100'),
(2, 'NIKE CORTEZ', '1', '12', '104'),
(3, 'ADIDAS PANTS', '2', '27', '238'),
(4, 'PUMA REVOLUTION 5', '3', '35', '374'),
(5, 'SALOMON SHELTER CS', '4', '15', '135'),
(6, 'NIKE EBERNON LOW', '2', '14', '157');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
SELECT prod.ID,
prod.DESCRIPTION,
CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
FROM @PRODUCTS AS prod
LEFT JOIN @CATS AS cat1 ON cat1.ID = prod.CAT
LEFT JOIN @SUBCATS AS cat2 ON cat2.ID = prod.SUBCAT
LEFT JOIN @SUBSUBCATS AS cat3 ON cat3.ID = prod.SUBSUBCAT;
现在假设 @PRODUCTS
table 上的外键不仅仅是它们各自 table 的索引。它们是多个类别、子类别和子类别的逗号分隔索引,例如 here.
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6', '27, 35', '238, 374');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
SELECT prod.ID,
prod.DESCRIPTION
--CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
FROM @PRODUCTS AS prod
--LEFT JOIN @CATS AS cat1 ON cat1.ID = prod.CAT
--LEFT JOIN @SUBCATS AS cat2 ON cat2.ID = prod.SUBCAT
--LEFT JOIN @SUBSUBCATS AS cat3 ON cat3.ID = prod.SUBSUBCAT;
在这种情况下,我想实现以下目标:
- 能够检索猫、子猫、子子猫的各自名称,即。对于猫 '1, 2' 能够检索它们的名字(我试过
LEFT JOIN @CATS AS cat1 ON cat1.ID IN prod.CAT
但它不起作用)
- 创建相应猫、子猫、子子猫的三胞胎,即。对于
- 猫“1、2”
- 子猫 '12, 17'
- sub-subcats '239, 372'
(检索到适当的名称后)创建管道分隔的类别 routes like name of cat 1
> name of subcat 12
> name of sub-subcat 239
| name of cat 2
> name of subcat 17
> name of sub-subcat 372
所以,对于 (1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
这样的行
我想得到以下结果
ID
DESCRIPTION
CATEGORIES
1
NIKE MILLENIUM
MEN > FOOTWEAR > RUNNING @ WOMEN > OUTERWEAR > FLEECE (I had to use @ as the delimiter of the two triplets because pipe messed with the table's columns)
如果用户愚蠢地存储了比子猫 ID 或子子猫 ID 多的猫 ID,查询应该只匹配具有相应位置匹配的猫 ID,即 for
- 猫“1、2”
- 子猫'12'
- sub-subcats '239, 372'
它应该只创建一个三元组,例如 name of 1
> name of 12
> name of 239
STRING_SPLIT()
不承诺 return 特定顺序的值,因此在这种情况下它不起作用,因为顺序位置很重要。
使用 OPENJSON()
将字符串拆分为单独的行以确保值 return 以相同的顺序编辑。
OPENJSON()
也 return 是一个 key
字段,因此您可以在每个分组中加入行号。您需要一个 INNER JOIN
,因为您的要求是该“列”中的所有值都必须存在。
使用 STUFF()
到 assemble 各种 cat>subcat>subsubcat 值。
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6, 1', '27, 35, 10', '238, 374, 100'),
(4, 'JOE THE PLUMBER JEANS', '1, 5', '27', '238, 374');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
;
with prod as (
SELECT p.ID,
p.DESCRIPTION
--CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
, c.value as CatId
, c.[key] as CatKey
, sc.value as SubCatId
, sc.[key] as SubCatKey
, ssc.value as SubSubCatId
, ssc.[key] as SubSubCatKey
FROM @PRODUCTS p
cross apply OPENJSON(CONCAT('["', REPLACE(cat, ', ', '","'), '"]')) c
cross apply OPENJSON(CONCAT('["', REPLACE(subcat, ', ', '","'), '"]')) sc
cross apply OPENJSON(CONCAT('["', REPLACE(subsubcat, ', ', '","'), '"]')) ssc
where c.[key] = sc.[key]
and c.[key] = ssc.[key]
)
, a as (
select p.ID
, p.DESCRIPTION
, c.DESCR + ' > ' + sc.DESCR + ' > ' + ssc.DESCR as CATEGORIES
, p.CatKey
from prod p
inner join @CATS c on c.ID = p.CatId
inner join @SUBCATS sc on sc.ID = p.SubCatId
inner join @SUBSUBCATS ssc on ssc.ID = p.SubSubCatId
)
select DISTINCT ID
, DESCRIPTION
, replace(STUFF((SELECT distinct ' | ' + a2.CATEGORIES
from a a2
where a.ID = a2.ID
FOR XML PATH(''))
,1,2,''), '>', '>') CATEGORIES
from a
那应该行得通,我把你的字符“>”换成“-”只是为了让数据更简单。
您的表格设计并不完美,但第一次尝试几乎不会完美。
select mainp.ID, mainp.DESCRIPTION, stuff(ppaths.metapaths, len(ppaths.metapaths),1,'') metalinks
from @PRODUCTS mainp
cross apply(
select
(select
c.DESCR + '-' + sc.DESCR + '-' + sbc.DESCR + '|'
from @PRODUCTS p
cross apply (select row_number() over(order by Value) id, Value from split(p.CAT, ','))cat_ids
inner join @cats c on c.ID = cat_ids.Value
cross apply (select row_number() over(order by Value) id, Value from split(p.SUBCAT, ','))subcat_ids
inner join @SUBCATS sc on sc.ID = subcat_ids.Value
and subcat_ids.id = subcat_ids.id
cross apply (select row_number() over(order by Value) id, Value from split(p.SUBSUBCAT, ','))subsubcat_ids
inner join @SUBSUBCATS sbc on sbc.ID = subsubcat_ids.Value
and subsubcat_ids.id = subcat_ids.id
where p.id = mainp.ID
for xml path('')) metapaths
) ppaths
link 拆分功能
https://desarrolladores.me/2014/03/sql-server-funcion-split-para-dividir-un-string/
由于对旧技术的更改,答案完全不同。我认为我原来的答案对使用当前 SQL 服务器版本的人来说仍然很好,所以我不想删除它。
我不记得我从哪里得到的函数。当我今天找到它时,它被命名为 split_delimiter。我更改了名称,添加了一些注释,并合并了一个长度超过一个字符的分隔符的功能。
CREATE FUNCTION [dbo].[udf_split_string](@delimited_string VARCHAR(8000), @delimiter varchar(10))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS ( -- 10 rows
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
, cte100(num) AS ( -- 100 rows
SELECT 1
FROM cte10 t1, cte10 t2
)
, cte10000(num) AS ( -- 10000 rows
SELECT 1
FROM cte100 t1, cte100 t2
)
, cte1(num) AS ( -- 1 row per character
SELECT TOP (ISNULL(DATALENGTH(@delimited_string), 0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
, cte2(num) AS ( -- locations of strings
SELECT 1
UNION ALL
SELECT t.num + len(replace(@delimiter, ' ', '_'))
FROM cte1 t
WHERE SUBSTRING(@delimited_string, t.num, len(replace(@delimiter, ' ', '_'))) = @delimiter
)
, cte3(num, [len]) AS (
SELECT t.num
, ISNULL(NULLIF(CHARINDEX(@delimiter, @delimited_string, t.num), 0) - t.num, 8000)
FROM cte2 t
)
SELECT [Key] = ROW_NUMBER() OVER (ORDER BY t.num)
, [Value] = SUBSTRING(@delimited_string, t.num, t.[len])
FROM cte3 t;
GO
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6, 1', '27, 35, 10', '238, 374, 100'),
(4, 'JOE THE PLUMBER JEANS', '1, 5', '27', '238, 374');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
;
with prod as (
SELECT p.ID,
p.DESCRIPTION
, c.value as CatId
, c.[key] as CatKey
, sc.value as SubCatId
, sc.[key] as SubCatKey
, ssc.value as SubSubCatId
, ssc.[key] as SubSubCatKey
FROM @PRODUCTS p
cross apply dbo.udf_split_string(cat, ', ') c
cross apply dbo.udf_split_string(subcat, ', ') sc
cross apply dbo.udf_split_string(subsubcat, ', ') ssc
where c.[key] = sc.[key]
and c.[key] = ssc.[key]
)
, a as (
select p.ID
, p.DESCRIPTION
, c.DESCR + ' > ' + sc.DESCR + ' > ' + ssc.DESCR as CATEGORIES
, p.CatKey
from prod p
inner join @CATS c on c.ID = p.CatId
inner join @SUBCATS sc on sc.ID = p.SubCatId
inner join @SUBSUBCATS ssc on ssc.ID = p.SubSubCatId
)
select DISTINCT ID
, DESCRIPTION
, replace(STUFF((SELECT distinct ' | ' + a2.CATEGORIES
from a a2
where a.ID = a2.ID
FOR XML PATH(''))
,1,2,''), '>', '>') CATEGORIES
from a
假设以下简单 scenario,其中产品行连接到一个主要类别、子类别和子类别。
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1', '10', '100'),
(2, 'NIKE CORTEZ', '1', '12', '104'),
(3, 'ADIDAS PANTS', '2', '27', '238'),
(4, 'PUMA REVOLUTION 5', '3', '35', '374'),
(5, 'SALOMON SHELTER CS', '4', '15', '135'),
(6, 'NIKE EBERNON LOW', '2', '14', '157');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
SELECT prod.ID,
prod.DESCRIPTION,
CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
FROM @PRODUCTS AS prod
LEFT JOIN @CATS AS cat1 ON cat1.ID = prod.CAT
LEFT JOIN @SUBCATS AS cat2 ON cat2.ID = prod.SUBCAT
LEFT JOIN @SUBSUBCATS AS cat3 ON cat3.ID = prod.SUBSUBCAT;
现在假设 @PRODUCTS
table 上的外键不仅仅是它们各自 table 的索引。它们是多个类别、子类别和子类别的逗号分隔索引,例如 here.
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6', '27, 35', '238, 374');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
SELECT prod.ID,
prod.DESCRIPTION
--CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
FROM @PRODUCTS AS prod
--LEFT JOIN @CATS AS cat1 ON cat1.ID = prod.CAT
--LEFT JOIN @SUBCATS AS cat2 ON cat2.ID = prod.SUBCAT
--LEFT JOIN @SUBSUBCATS AS cat3 ON cat3.ID = prod.SUBSUBCAT;
在这种情况下,我想实现以下目标:
- 能够检索猫、子猫、子子猫的各自名称,即。对于猫 '1, 2' 能够检索它们的名字(我试过
LEFT JOIN @CATS AS cat1 ON cat1.ID IN prod.CAT
但它不起作用) - 创建相应猫、子猫、子子猫的三胞胎,即。对于
- 猫“1、2”
- 子猫 '12, 17'
- sub-subcats '239, 372'
(检索到适当的名称后)创建管道分隔的类别 routes like name of cat 1
> name of subcat 12
> name of sub-subcat 239
| name of cat 2
> name of subcat 17
> name of sub-subcat 372
所以,对于 (1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
我想得到以下结果
ID | DESCRIPTION | CATEGORIES |
---|---|---|
1 | NIKE MILLENIUM | MEN > FOOTWEAR > RUNNING @ WOMEN > OUTERWEAR > FLEECE (I had to use @ as the delimiter of the two triplets because pipe messed with the table's columns) |
如果用户愚蠢地存储了比子猫 ID 或子子猫 ID 多的猫 ID,查询应该只匹配具有相应位置匹配的猫 ID,即 for
- 猫“1、2”
- 子猫'12'
- sub-subcats '239, 372'
它应该只创建一个三元组,例如 name of 1
> name of 12
> name of 239
STRING_SPLIT()
不承诺 return 特定顺序的值,因此在这种情况下它不起作用,因为顺序位置很重要。
使用 OPENJSON()
将字符串拆分为单独的行以确保值 return 以相同的顺序编辑。
OPENJSON()
也 return 是一个 key
字段,因此您可以在每个分组中加入行号。您需要一个 INNER JOIN
,因为您的要求是该“列”中的所有值都必须存在。
使用 STUFF()
到 assemble 各种 cat>subcat>subsubcat 值。
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6, 1', '27, 35, 10', '238, 374, 100'),
(4, 'JOE THE PLUMBER JEANS', '1, 5', '27', '238, 374');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
;
with prod as (
SELECT p.ID,
p.DESCRIPTION
--CONCAT(cat1.DESCR, ' > ', cat2.DESCR, ' > ', cat3.DESCR) AS CATEGORIES
, c.value as CatId
, c.[key] as CatKey
, sc.value as SubCatId
, sc.[key] as SubCatKey
, ssc.value as SubSubCatId
, ssc.[key] as SubSubCatKey
FROM @PRODUCTS p
cross apply OPENJSON(CONCAT('["', REPLACE(cat, ', ', '","'), '"]')) c
cross apply OPENJSON(CONCAT('["', REPLACE(subcat, ', ', '","'), '"]')) sc
cross apply OPENJSON(CONCAT('["', REPLACE(subsubcat, ', ', '","'), '"]')) ssc
where c.[key] = sc.[key]
and c.[key] = ssc.[key]
)
, a as (
select p.ID
, p.DESCRIPTION
, c.DESCR + ' > ' + sc.DESCR + ' > ' + ssc.DESCR as CATEGORIES
, p.CatKey
from prod p
inner join @CATS c on c.ID = p.CatId
inner join @SUBCATS sc on sc.ID = p.SubCatId
inner join @SUBSUBCATS ssc on ssc.ID = p.SubSubCatId
)
select DISTINCT ID
, DESCRIPTION
, replace(STUFF((SELECT distinct ' | ' + a2.CATEGORIES
from a a2
where a.ID = a2.ID
FOR XML PATH(''))
,1,2,''), '>', '>') CATEGORIES
from a
那应该行得通,我把你的字符“>”换成“-”只是为了让数据更简单。
您的表格设计并不完美,但第一次尝试几乎不会完美。
select mainp.ID, mainp.DESCRIPTION, stuff(ppaths.metapaths, len(ppaths.metapaths),1,'') metalinks
from @PRODUCTS mainp
cross apply(
select
(select
c.DESCR + '-' + sc.DESCR + '-' + sbc.DESCR + '|'
from @PRODUCTS p
cross apply (select row_number() over(order by Value) id, Value from split(p.CAT, ','))cat_ids
inner join @cats c on c.ID = cat_ids.Value
cross apply (select row_number() over(order by Value) id, Value from split(p.SUBCAT, ','))subcat_ids
inner join @SUBCATS sc on sc.ID = subcat_ids.Value
and subcat_ids.id = subcat_ids.id
cross apply (select row_number() over(order by Value) id, Value from split(p.SUBSUBCAT, ','))subsubcat_ids
inner join @SUBSUBCATS sbc on sbc.ID = subsubcat_ids.Value
and subsubcat_ids.id = subcat_ids.id
where p.id = mainp.ID
for xml path('')) metapaths
) ppaths
link 拆分功能 https://desarrolladores.me/2014/03/sql-server-funcion-split-para-dividir-un-string/
由于对旧技术的更改,答案完全不同。我认为我原来的答案对使用当前 SQL 服务器版本的人来说仍然很好,所以我不想删除它。
我不记得我从哪里得到的函数。当我今天找到它时,它被命名为 split_delimiter。我更改了名称,添加了一些注释,并合并了一个长度超过一个字符的分隔符的功能。
CREATE FUNCTION [dbo].[udf_split_string](@delimited_string VARCHAR(8000), @delimiter varchar(10))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS ( -- 10 rows
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
, cte100(num) AS ( -- 100 rows
SELECT 1
FROM cte10 t1, cte10 t2
)
, cte10000(num) AS ( -- 10000 rows
SELECT 1
FROM cte100 t1, cte100 t2
)
, cte1(num) AS ( -- 1 row per character
SELECT TOP (ISNULL(DATALENGTH(@delimited_string), 0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
, cte2(num) AS ( -- locations of strings
SELECT 1
UNION ALL
SELECT t.num + len(replace(@delimiter, ' ', '_'))
FROM cte1 t
WHERE SUBSTRING(@delimited_string, t.num, len(replace(@delimiter, ' ', '_'))) = @delimiter
)
, cte3(num, [len]) AS (
SELECT t.num
, ISNULL(NULLIF(CHARINDEX(@delimiter, @delimited_string, t.num), 0) - t.num, 8000)
FROM cte2 t
)
SELECT [Key] = ROW_NUMBER() OVER (ORDER BY t.num)
, [Value] = SUBSTRING(@delimited_string, t.num, t.[len])
FROM cte3 t;
GO
DECLARE @PRODUCTS TABLE (ID int, DESCRIPTION varchar(50), CAT varchar(30), SUBCAT varchar(30), SUBSUBCAT varchar(30));
INSERT @PRODUCTS (ID, DESCRIPTION, CAT, SUBCAT, SUBSUBCAT) VALUES
(1, 'NIKE MILLENIUM', '1, 2', '10, 12', '100, 135'),
(2, 'NIKE CORTEZ', '1, 5', '12, 15', '104, 374'),
(3, 'ADIDAS PANTS', '2, 6, 1', '27, 35, 10', '238, 374, 100'),
(4, 'JOE THE PLUMBER JEANS', '1, 5', '27', '238, 374');
DECLARE @CATS TABLE (ID int, DESCR varchar(100));
INSERT @CATS (ID, DESCR) VALUES
(1, 'MEN'),
(2, 'WOMEN'),
(3, 'UNISEX'),
(4, 'KIDS'),
(5, 'TEENS'),
(6, 'BACK TO SCHOOL');
DECLARE @SUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBCATS (ID, DESCR) VALUES
(10, 'FOOTWEAR'),
(12, 'OUTERWEAR'),
(14, 'SWIMWEAR'),
(15, 'HOODIES'),
(27, 'CLOTHING'),
(35, 'SPORTS');
DECLARE @SUBSUBCATS TABLE (ID int, DESCR varchar(100));
INSERT @SUBSUBCATS (ID, DESCR) VALUES
(100, 'RUNNING'),
(104, 'ZIP TOPS'),
(135, 'FLEECE'),
(157, 'BIKINIS'),
(238, 'PANTS'),
(374, 'JOGGERS');
;
with prod as (
SELECT p.ID,
p.DESCRIPTION
, c.value as CatId
, c.[key] as CatKey
, sc.value as SubCatId
, sc.[key] as SubCatKey
, ssc.value as SubSubCatId
, ssc.[key] as SubSubCatKey
FROM @PRODUCTS p
cross apply dbo.udf_split_string(cat, ', ') c
cross apply dbo.udf_split_string(subcat, ', ') sc
cross apply dbo.udf_split_string(subsubcat, ', ') ssc
where c.[key] = sc.[key]
and c.[key] = ssc.[key]
)
, a as (
select p.ID
, p.DESCRIPTION
, c.DESCR + ' > ' + sc.DESCR + ' > ' + ssc.DESCR as CATEGORIES
, p.CatKey
from prod p
inner join @CATS c on c.ID = p.CatId
inner join @SUBCATS sc on sc.ID = p.SubCatId
inner join @SUBSUBCATS ssc on ssc.ID = p.SubSubCatId
)
select DISTINCT ID
, DESCRIPTION
, replace(STUFF((SELECT distinct ' | ' + a2.CATEGORIES
from a a2
where a.ID = a2.ID
FOR XML PATH(''))
,1,2,''), '>', '>') CATEGORIES
from a