SQL:在单个字段中包含多个值的嵌套 SELECT
在我的 SQL 2005 DB 中,我有一个表,其中的值存储为 ID,并与其他表有关系。因此,在我的 MyDBO.warranty 表中,我存储的是product_id 而不是product_name 以节省空间。产品名称存储在MyDBO.products中。
当营销部门提取人口统计信息时,查询从相关表中为每个 ID 选择相应的名称(为了简洁而进行了精简):
SELECT w1.warranty_id AS "No.",
w1.created AS "Register Date"
w1.full_name AS "Name",
w1.purchase_date AS "Purchased",
(
SELECT p1.product_name
FROM WarrDBO.products p1 WITH(NOLOCK)
WHERE p1.product_id = i1.product_id
) AS "Product Purchased",
i1.accessories
FROM WarrDBO.warranty w1
LEFT OUTER JOIN WarrDBO.warranty_info i1
ON i1.warranty_id = w1.warranty_id
ORDER BY w1.warranty_id ASC
现在,我的问题是保修信息表上的“配件”列存储了几个值:
No. Register Date Name Purchased Accessories
---------------------------------------------------------------------
1500 1/1/2008 Smith, John Some Product 5,7,9
1501 1/1/2008 Hancock, John Another 2,3
1502 1/1/2008 Brown, James And Another 2,9
我需要对“Accessories”执行与“Product”类似的操作,并使用 accessory_id< 从 MyDBO.accessories 表中提取 accessory_name /强>。我不知道从哪里开始,因为首先我需要提取 ID,然后以某种方式将多个值连接成一个字符串。因此,每一行都会有“accessoryname1,accessoryname2,accessoryname3”:
No. Register Date Name Purchased Accessories
---------------------------------------------------------------------
1500 1/1/2008 Smith, John Some Product Case,Bag,Padding
1501 1/1/2008 Hancock, John Another Wrap,Label
1502 1/1/2008 Brown, James And Another Wrap,Padding
我该怎么做?
编辑>>发布我的最终代码:
我创建了这个函数:
CREATE FUNCTION SQL_GTOInc.Split
(
@delimited varchar(50),
@delimiter varchar(1)
) RETURNS @t TABLE
(
-- Id column can be commented out, not required for sql splitting string
id INT identity(1,1), -- I use this column for numbering splitted parts
val INT
)
AS
BEGIN
declare @xml xml
set @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'
insert into @t(val)
select
r.value('.','varchar(5)') as item
from @xml.nodes('//root/r') as records(r)
RETURN
END
并相应地更新了我的代码:
SELECT w1.warranty_id,
i1.accessories,
(
CASE
WHEN i1.accessories <> '' AND i1.accessories <> 'NULL' AND LEN(i1.accessories) > 0 THEN
STUFF(
(
SELECT ', ' + a1.accessory
FROM MyDBO.accessories a1
INNER JOIN MyDBO.Split(i1.accessories, ',') a2
ON a1.accessory_id = a2.val
FOR XML PATH('')
), 1, 1, ''
)
ELSE ''
END
) AS "Accessories"
FROM MyDBO.warranty w1
LEFT OUTER JOIN MyDBO.warranty_info i1
ON i1.warranty_id = w1.warranty_id
In my SQL 2005 DB, I have a table with values stored as IDs with relationships to other tables. So in my MyDBO.warranty table, I'm storing product_id instead of product_name in order to save space. The product_name is stored in MyDBO.products.
When the marketing department pulls the demographic information, the query selects the corresponding name for each ID from related tables (trimmed down for brevity):
SELECT w1.warranty_id AS "No.",
w1.created AS "Register Date"
w1.full_name AS "Name",
w1.purchase_date AS "Purchased",
(
SELECT p1.product_name
FROM WarrDBO.products p1 WITH(NOLOCK)
WHERE p1.product_id = i1.product_id
) AS "Product Purchased",
i1.accessories
FROM WarrDBO.warranty w1
LEFT OUTER JOIN WarrDBO.warranty_info i1
ON i1.warranty_id = w1.warranty_id
ORDER BY w1.warranty_id ASC
Now, my problem is that the "accessories" column on the warranty_info table stores several values:
No. Register Date Name Purchased Accessories
---------------------------------------------------------------------
1500 1/1/2008 Smith, John Some Product 5,7,9
1501 1/1/2008 Hancock, John Another 2,3
1502 1/1/2008 Brown, James And Another 2,9
I need to do something similar with "Accessories" that I did with "Product" and pull accessory_name from the MyDBO.accessories table using accessory_id. I'm not sure where to start, because first I'd need to extract the IDs and then somehow concatenate multiple values into a string. So each line would have "accessoryname1,accessoryname2,accessoryname3":
No. Register Date Name Purchased Accessories
---------------------------------------------------------------------
1500 1/1/2008 Smith, John Some Product Case,Bag,Padding
1501 1/1/2008 Hancock, John Another Wrap,Label
1502 1/1/2008 Brown, James And Another Wrap,Padding
How do I do this?
EDIT>> Posting my final code:
I created this function:
CREATE FUNCTION SQL_GTOInc.Split
(
@delimited varchar(50),
@delimiter varchar(1)
) RETURNS @t TABLE
(
-- Id column can be commented out, not required for sql splitting string
id INT identity(1,1), -- I use this column for numbering splitted parts
val INT
)
AS
BEGIN
declare @xml xml
set @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'
insert into @t(val)
select
r.value('.','varchar(5)') as item
from @xml.nodes('//root/r') as records(r)
RETURN
END
And updated my code accordingly:
SELECT w1.warranty_id,
i1.accessories,
(
CASE
WHEN i1.accessories <> '' AND i1.accessories <> 'NULL' AND LEN(i1.accessories) > 0 THEN
STUFF(
(
SELECT ', ' + a1.accessory
FROM MyDBO.accessories a1
INNER JOIN MyDBO.Split(i1.accessories, ',') a2
ON a1.accessory_id = a2.val
FOR XML PATH('')
), 1, 1, ''
)
ELSE ''
END
) AS "Accessories"
FROM MyDBO.warranty w1
LEFT OUTER JOIN MyDBO.warranty_info i1
ON i1.warranty_id = w1.warranty_id
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以编写一个表值函数,该函数只需将逗号分隔的字符串拆分为 XML 并将 XML 节点转换为行。
看:
http://www.kodyaz.com /articles//t-sql-convert-split-delimed-string-as-rows-using-xml.aspx
通过函数调用的结果加入附件,并将结果填充回逗号分隔的名称列表。
未经测试的代码:
You could write a table valued function that simply splits comma separated string into XML and turns XML nodes to rows.
See:
http://www.kodyaz.com/articles//t-sql-convert-split-delimeted-string-as-rows-using-xml.aspx
Join to accessories through the result of function call, and stuff the result back to comma separated list of names.
Untested code:
与你的问题无关。请注意,您也可以编写原始查询,将子查询移动到联接,如下所示:
Nothing to do with your question. Just a note that your original query can also be written, moving the subqery to a join, as:
您只需要使用 SQL Server 的 FOR XML 功能即可easy cat strings:
链接博客文章中的示例:
要解析已存储为逗号分隔的字段,您必须编写一个 UDF 来解析该字段并返回一个表,然后可以将其与 WHERE 中的 IN 谓词一起使用条款。请参阅这里了解初学者,以及此处。
You just need to use the FOR XML feature of SQL Server to easily cat strings:
Example from the linked blog post:
To parse a field that has already been stored as comma delimited you will have to write a UDF that parses the field and returns a table which can then be used with an IN predicate in your WHERE clause. Look here for starters, and here.
这似乎是连接聚合函数的工作。
在 SQL 中,可以使用 CLR
http://www.mssqltips.com/tip.asp 进行部署?tip=2022
It seem to be a work for a concatenate aggregate function.
In SQL it can be deployed using CLR
http://www.mssqltips.com/tip.asp?tip=2022