我是SQL的新手,我正试图弄清楚如何在While Exists条件循环中使用Select语句中的值。目的是将Document的一个属性的多个出现组合成一个字段,然后将这些结果转换并连接到Document记录。
例如,存在三个表,如下所示:
ID,ATTRIBUTE_NAME
---------------------------
1,创建
2,Embedded_Image
...
ATTRIBUTE_ID,VALUE,DOC_ID
-------------------------------------------
1,2010 / 11 / 01,1
2,'Home.png',1
2,'Castle.png',1
2,'Apartment.jpg',1
1,2008 / 06 / 23,2
2,'Ski Jump.jpg',2
2,'Snowboarding.png',2
...
ID,TEXT
---------------------------
1,'家的......'
2,'冬季运动......'
...
因此最终的Pivot和表的连接看起来像这样:
我尝试编写的SQL While Exists条件看起来像这样:
DECLARE @LOOP_DOC_ID UNIQUEIDENTIFIER
DECLARE @LOOP_ATTRIBUTE_NAME NVARCHAR(MAX)
WHILE EXISTS(
SELECT [dbo].[ATTRIBUTE_VALUES].[DOC_ID], [dbo].[ATTRIBUTES].[ATTRIBUTE_NAME]
FROM ([dbo].[ATTRIBUTE_VALUES] INNER JOIN [dbo].[ATTRIBUTES]
ON [dbo].[ATTRIBUTE_VALUES].[ATTRIBUTE_ID] = [dbo].[ATTRIBUTES].[ID])
)
BEGIN
SET @LOOP_DOC_ID = DOC_ID
SET @LOOP_ATTRIBUTE_NAME = ATTRIBUTE_NAME
SELECT STUFF(
(
SELECT DISTINCT ',' + RTRIM(LTRIM([dbo].[ATTRIBUTE_VALUES].[VALUE]))
FROM
(
[dbo].[ATTRIBUTE_VALUES] INNER JOIN [dbo].[ATTRIBUTES]
ON [dbo].[ATTRIBUTE_VALUES].[ATTRIBUTE_ID] = [dbo].[ATTRIBUTES].[ID]
)
WHERE [dbo].[ATTRIBUTE_VALUES].[DOC_ID] = @LOOP_DOC_ID
AND [dbo].[ATTRIBUTES].[ATTRIBUTE_NAME] = @LOOP_ATTRIBUTE_NAME
ORDER BY ',' + RTRIM(LTRIM([dbo].[ATTRIBUTE_VALUES].[VALUE]))
FOR XML PATH('')
), 1, 2, ''
) AS VALUE, @LOOP_DOC_ID AS DOC_ID, @LOOP_ATTRIBUTE_NAME AS ATTRIBUTE_NAME
END
SQL Server不喜欢我试图将变量设置为While Exists条件中Select语句的值的行。
如何使用[dbo]。[ATTRIBUTE_VALUES]。[DOC_ID],[dbo]。[ATTRIBUTES]。[ATTRIBUTE_NAME]值在BEGIN和END语句之间的While Exists条件语句中选择?
我希望取消@LOOP_DOC_ID和@LOOP_ATTRIBUTE_NAME变量并直接处理这些值。
我已经浏览过讨论使用游标来解决类似问题的论坛,但是他们中的每一个似乎都建议仅使用游标作为最后的手段,因为它们缺乏速度。我也看到有些人使用存储过程,但我不能使用它们,因为我的老板已将这些作为禁区。我需要一个光标,还是有更好的方法来做到这一点?
答案 0 :(得分:2)
看看这样的事情(完整示例)
DECLARE @ATTRIBUTES TABLE(
ID INT,
ATTRIBUTE_NAME VARCHAR(100)
)
INSERT INTO @ATTRIBUTES SELECT 1, 'Created'
INSERT INTO @ATTRIBUTES SELECT 2, 'Embedded_Image'
DECLARE @ATTRIBUTE_VALUES TABLE(
ATTRIBUTE_ID INT,
VALUE VARCHAR(100),
DOC_ID INT
)
INSERT INTO @ATTRIBUTE_VALUES SELECT 1, '2010/11/01', 1
INSERT INTO @ATTRIBUTE_VALUES SELECT 2, 'Home.png', 1
INSERT INTO @ATTRIBUTE_VALUES SELECT 2, 'Castle.png', 1
INSERT INTO @ATTRIBUTE_VALUES SELECT 2, 'Apartment.jpg', 1
INSERT INTO @ATTRIBUTE_VALUES SELECT 1, '2008/06/23', 2
INSERT INTO @ATTRIBUTE_VALUES SELECT 2, 'Ski Jump.jpg', 2
INSERT INTO @ATTRIBUTE_VALUES SELECT 2, 'Snowboarding.png', 2
DECLARE @DOCUMENTS TABLE(
ID INT,
[TEXT] VARCHAR(100)
)
INSERT INTO @DOCUMENTS SELECT 1, 'Homes of the ...'
INSERT INTO @DOCUMENTS SELECT 2, 'Winter sports ...'
;WITH Vals AS (
SELECT d.ID DOC_ID,
d.[TEXT] [TEXT],
a.ATTRIBUTE_NAME,
av.VALUE
FROM @DOCUMENTS d INNER JOIN
@ATTRIBUTE_VALUES av ON d.ID = av.DOC_ID INNER JOIN
@ATTRIBUTES a ON av.ATTRIBUTE_ID = a.ID
)
SELECT *
FROM (
SELECT DOC_ID,
[TEXT],
ATTRIBUTE_NAME,
stuff(
(
select ',' + t.VALUE
from Vals t
where t.DOC_ID = v.DOC_ID
AND t.ATTRIBUTE_NAME = v.ATTRIBUTE_NAME
order by t.VALUE
for xml path('')
),1,1,'') Concats
FROM Vals v
GROUP BY DOC_ID,
[TEXT],
ATTRIBUTE_NAME
) s
PIVOT ( MAX(ConCats) FOR ATTRIBUTE_NAME IN ([Created],[Embedded_Image])) pvt
输出
DOC_ID TEXT Created Embedded_Image
1 Homes of the ... 2010/11/01 Apartment.jpg,Castle.png,Home.png
2 Winter sports ... 2008/06/23 Ski Jump.jpg,Snowboarding.png
答案 1 :(得分:0)
从你的样本中,在常识的支持下,我冒险尝试了
因此,在创建日期上转动非常简单:
SELECT DOC_ID
, VALUE AS Created
FROM ATTRIBUTE_VALUES
WHERE ATTRIBUTE_ID = 1
并将此子查询连接到Documents表格,可以得到所需输出的前三列。
您的最后一列总结了每个文档的多个嵌入图像。我个人会使用一些标准的报告工具(例如MS Access或Crystal Reports)。或者,使用您的四个所需列创建一个新的空表,使用SQL INSERT语句填充前三列,然后使用Perl(或C#,或您最喜欢的声明性语言)查询每个文档的嵌入图像,连接结果用逗号,并将连接插入第四列。
但是如果你想在SQL中这样做,之前已经在这里询问了连接多值问题,例如在How to create a SQL Server function to "join" multiple rows from a subquery into a single delimited field?。