Как я могу использовать значения, выбранные в операторе while Exists внутри цикла While? - PullRequest
1 голос
/ 30 ноября 2010

Я новичок в SQL и пытаюсь выяснить, как использовать значения из оператора Select в условном цикле While Exists. Цель состоит в том, чтобы объединить несколько экземпляров атрибута для документа в одно поле, а затем развернуть и объединить эти результаты с записью документа.

Например, три таблицы существуют примерно так:




Таким образом, окончательные сводные таблицы и соединения будут выглядеть так:


Условие SQL пока существует, которое я пытался написать, выглядит так:


    DECLARE @LOOP_DOC_ID UNIQUEIDENTIFIER
    DECLARE @LOOP_ATTRIBUTE_NAME NVARCHAR(MAX)<br>
    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<br>
      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 не нравятся строки, в которых я пытаюсь установить переменные в значения из оператора Select в условии while Exists.

Как использовать значения [dbo]. [ATTRIBUTE_VALUES]. [DOC_ID], [dbo]. [ATTRIBUTES]. [ATTRIBUTE_NAME] Выбранные в условном выражении while Exists между операторами BEGIN и END?

Предпочтительно я хотел бы покончить с переменными @LOOP_DOC_ID и @LOOP_ATTRIBUTE_NAME и иметь дело непосредственно со значениями.

Я просматривал форумы, на которых говорилось об использовании курсоров для решения похожих проблем, но каждый из них, похоже, рекомендует использовать курсоры только в качестве крайней меры из-за недостатка скорости. Я также видел, как некоторые люди используют хранимые процедуры, но я не могу их использовать, так как мой босс считает их запрещенными. Мне нужен курсор или есть лучший способ сделать это?

Ответы [ 2 ]

2 голосов
/ 30 ноября 2010

Посмотрите на что-то вроде этого ( Полный пример )

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
0 голосов
/ 30 ноября 2010

Из вашего примера и с поддержкой здравого смысла я рискну предположить, что

  1. Документ имеет одну дату создания.
  2. Документ может иметь много встроенных изображений.

Таким образом, поворот даты создания прост:

SELECT DOC_ID
, VALUE AS Created
FROM ATTRIBUTE_VALUES
WHERE ATTRIBUTE_ID = 1

, и при присоединении этого подзапроса к таблице документов вы получите первые три столбца желаемого результата.

Ваш последний столбец суммирует несколько встроенных изображений для каждого документа.Лично я бы использовал какой-нибудь стандартный инструмент отчетности (например, MS Access или Crystal Reports).Либо создайте новую пустую таблицу с четырьмя нужными столбцами, заполните первые три столбца оператором SQL INSERT, а затем выполните Perl (или C #, или ваш любимый декларативный язык) запрос для встроенных изображений каждого документа, объедините результатыс запятыми и вставьте конкатенацию в четвертый столбец.

Но если вы хотите сделать это в SQL, вопрос о concatenate-множественных значениях уже задавался здесь, например, в Как создатьФункция SQL Server для «объединения» нескольких строк из подзапроса в одно поле с разделителями? .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...