如何在While循环内的While Exists语句中使用Selected的值?

时间:2010-11-30 03:52:44

标签: sql sql-server tsql

我是SQL的新手,我正试图弄清楚如何在While Exists条件循环中使用Select语句中的值。目的是将Document的一个属性的多个出现组合成一个字段,然后将这些结果转换并连接到Document记录。

例如,存在三个表,如下所示:

    ATTRIBUTES TABLE

    ID,ATTRIBUTE_NAME
    ---------------------------
    1,创建
    2,Embedded_Image
    ...


    ATTRIBUTE_VALUES TABLE

    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和表的连接看起来像这样:

    DOC_ID,TEXT,Created,Embedded_Image
    -------------------------------------------------- --------------------------------------
    1,'Homes of the ...',2010/11/01,'Home.png,Castle.png,Apartment.jpg'
    2,'冬季运动......',2008/06/23,'Ski Jump.jpg,Snowboarding.png'

我尝试编写的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变量并直接处理这些值。

我已经浏览过讨论使用游标来解决类似问题的论坛,但是他们中的每一个似乎都建议仅使用游标作为最后的手段,因为它们缺乏速度。我也看到有些人使用存储过程,但我不能使用它们,因为我的老板已将这些作为禁区。我需要一个光标,还是有更好的方法来做到这一点?

2 个答案:

答案 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)

从你的样本中,在常识的支持下,我冒险尝试了

  1. 文档只有一个创建日期。
  2. 文档可以包含许多嵌入的图像。
  3. 因此,在创建日期上转动非常简单:

    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?