【发布时间】:2011-07-27 23:28:49
【问题描述】:
在我的 SQL 2005 数据库中,我有一个表,其中的值存储为与其他表有关系的 ID。因此,在我的 MyDBO.warranty 表中,我存储的是 product_id 而不是 product_name 以节省空间。 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
现在,我的问题是warranty_info 表上的“附件”列存储了几个值:
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
我需要对“附件”执行与“产品”类似的操作,并从 MyDBO.accessories 表中提取 accessory_name使用 accessory_id。我不确定从哪里开始,因为首先我需要提取 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
【问题讨论】:
-
嗯,它(应该)不言而喻,但你不应该像这样在warranty_info 中存储附件列。您应该有一个连接表 Warranty_info_accessories,它包含两列:warranty_id 和 accessory_id。这将大大简化您的问题
-
我同意,如果我建造了这个结构,我会这样做。不幸的是,数据库作者竭尽全力节省空间,这是他使用的方法之一。
-
感谢所有帮助的人,如果我可以选择多个答案,我会的。显然我只是没有仔细阅读并在我的声明中遗漏了
FOR XML PATH(''),从而导致了错误。我已经采纳了所有建议,但效果并不理想。
标签: sql sql-server sql-server-2005 select