Результат таблицы SQL Server для массива в SQL Server 2005 - PullRequest
1 голос
/ 29 сентября 2011

Привет и заранее спасибо.

Во-первых, я не имею в виду, что я хочу преобразовать массив в таблицу.Я могу это сделать.Легко:)

Я хотел бы поступить наоборот.

У меня есть строка со n строками, относящимися к ней в другой таблице.Я хочу вывести строку, а затем в пределах одного столбца этой строки, скажем, Children, ее связанные строки в массив (или строку, которую я могу интерпретировать как массив с внешним кодом).

Примерно так:

ID   TITLE   DESCRIPTION   CHILDREN
--------------------------------------------------------
36   Blah    Blah Blah     ['Bob','Gary','Reginald']
20   Pah     Pah Pah       ['Emily','Dave']

Понимаете?

Я знаю, это, вероятно, не лучший способ сделать это.Но это для конкретного использования, которое было бы слишком долго объяснять здесь.

Еще раз спасибо.

Ответы [ 3 ]

2 голосов
/ 29 сентября 2011

Есть несколько способов сделать это; В статье ниже представлены различные решения для этого типа операции:

* ** 1003 тысячи два *http://www.simple -talk.com / SQL / T-SQL-программирование / конкатенация-строка-значения-в-Transact-SQL /
2 голосов
/ 29 сентября 2011

Вы можете сделать все это в одном запросе выбора CTE, без использования каких-либо функций. Вот как это сделать:

Сначала рассмотрим структуру родительской / дочерней таблицы:

CREATE TABLE P (ID INT PRIMARY KEY, Description VARCHAR(20));
CREATE TABLE C (ID INT PRIMARY KEY, PID INT, 
                Description VARCHAR(20), 
                CONSTRAINT fk FOREIGN KEY (PID) REFERENCES P(ID));

(я использую P и C, чтобы сэкономить при наборе текста!)

И давайте добавим несколько тестовых данных, совпадающих с данными вопроса:

INSERT INTO P VALUES (36, 'Blah Blah');
INSERT INTO P VALUES (20, 'Pah Pah');

INSERT INTO C VALUES (1, 36, 'Bob');
INSERT INTO C VALUES (2, 36, 'Gary');
INSERT INTO C VALUES (3, 36, 'Reginald');
INSERT INTO C VALUES (4, 20, 'Emily');
INSERT INTO C VALUES (5, 20, 'Dave');

Затем, наконец, выражение CTE:

WITH
FirstItems (PID, FirstCID) AS (    

    SELECT C.PID, MIN(C.ID)
      FROM C
     GROUP BY C.PID      
),  
SubItemList (PID, CID, ItemNum) AS (

    SELECT C.PID, C.ID, 1
      FROM C JOIN FirstItems FI ON (C.ID = FI.FirstCID)
    UNION ALL
    SELECT C.PID, C.ID, IL.ItemNum + 1
      FROM C JOIN SubItemList IL ON C.PID = IL.PID AND C.ID > CID
),
ItemList (PID, CID, ItemNum) AS (

    SELECT PID, CID, MAX(ItemNum)
      FROM SubItemList
     GROUP BY PID, CID
),
SubArrayList (PID, CID, Array, ItemNum) AS (

    SELECT IL.PID, IL.CID, CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
      FROM ItemList IL JOIN C ON IL.CID = C.ID
     WHERE IL.ItemNum = 1
    UNION ALL
    SELECT IL.PID, IL.CID, AL.Array + ',' + CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
      FROM ItemList IL
      JOIN SubArrayList AL ON (IL.PID = AL.PID AND IL.ItemNum = AL.ItemNum + 1)
      JOIN C ON (IL.CID = C.ID)
),
MaxItems (PID, MaxItem) AS (

    SELECT PID, MAX(ItemNum)
      FROM SubItemList
     GROUP BY PID

),
ArrayList (PID, List) AS (

    SELECT SAL.PID, SAL.Array
      FROM SubArrayList SAL 
      JOIN MaxItems MI ON (SAL.PID = MI.PID AND SAL.ItemNum = MI.MaxItem)

)
SELECT P.ID, P.Description, AL.List
  FROM ArrayList AL JOIN P ON P.ID = AL.PID
 ORDER BY P.ID

Результат:

ID Description    List
-- -------------- --------
20 Pah Pah        Emily,Dave
36 Blah Blah      Bob,Gary,Reginald   

Чтобы объяснить, что здесь происходит, я опишу каждую часть CTE и что она делает.

FirstItems просматривает все дочерние элементы и находит наименьший идентификатор в каждой родительской группе для использования в качестве привязки для следующего рекурсивного SELECT:

FirstItems (PID, FirstCID) AS (
    SELECT C.PID, MIN(C.ID)
      FROM C
     GROUP BY C.PID  
)

SubItemList - это рекурсивный SELECT, который выбирает младший дочерний элемент из предыдущего запроса и присваивает возрастающий номер элемента каждому дочернему элементу, начиная с 1:

SubItemList (PID, CID, ItemNum) AS (    
    SELECT C.PID, C.ID, 1
      FROM C JOIN FirstItems FI ON (C.ID = FI.FirstCID)
    UNION ALL
    SELECT C.PID, C.ID, IL.ItemNum + 1
      FROM C JOIN SubItemList IL ON C.PID = IL.PID AND C.ID > CID
)

Беда в том, что он всплывает и повторяет много предметов, поэтому ItemList фильтрует его, чтобы просто выбрать максимум из каждой группы:

ItemList (PID, CID, ItemNum) AS (
SELECT PID, CID, MAX(ItemNum)
  FROM SubItemList
 GROUP BY PID, CID
)

Теперь у нас есть идентификационный список родителей, каждый из которых пронумерован от 1 до x:

PID         CID         ItemNum
----------- ----------- -----------
36          1           1
36          2           2
36          3           3
20          4           1
20          5           2

SubArrayList берет дочерние строки, рекурсивно присоединяется к списку номеров и начинает добавлять все описания друг к другу, начиная с одного описания:

SubArrayList (PID, CID, Array, ItemNum) AS (    
    SELECT IL.PID, IL.CID, CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
      FROM ItemList IL JOIN C ON IL.CID = C.ID
     WHERE IL.ItemNum = 1
    UNION ALL
    SELECT IL.PID, IL.CID, AL.Array + ',' + CAST(C.Description AS VARCHAR(MAX)), IL.ItemNum
      FROM ItemList IL
      JOIN SubArrayList AL ON (IL.PID = AL.PID AND IL.ItemNum = AL.ItemNum + 1)
      JOIN C ON (IL.CID = C.ID)
)

Результат теперь:

PID         CID         Array             ItemNum
----------- ----------- ----------------- -----------
36          1           Bob               1
20          4           Emily             1
20          5           Emily,Dave        2
36          2           Bob,Gary          2
36          3           Bob,Gary,Reginald 3

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

MaxItems просто получает список родителей и их максимальные номера элементов, что упрощает следующий запрос:

MaxItems (PID, MaxItem) AS (    
    SELECT PID, MAX(ItemNum)
      FROM SubItemList
     GROUP BY PID        
)

ArrayList выполняет окончательный отбор частично сцепленных строк, используя максимальное количество элементов, полученное из предыдущего запроса:

ArrayList (PID, List) AS (
SELECT SAL.PID, SAL.Array
  FROM SubArrayList SAL 
  JOIN MaxItems MI ON (SAL.PID = MI.PID AND SAL.ItemNum = MI.MaxItem)     
)

И, наконец, остается только запросить результат:

SELECT P.ID, P.Description, AL.List
  FROM ArrayList AL JOIN P ON P.ID = AL.PID
 ORDER BY P.ID
1 голос
/ 29 сентября 2011

Вам нужна функция, которая при передаче внешнего ключа, который связывает дочернюю таблицу с родительской, запрашивает дочернюю таблицу для создания курсора, а затем проходит по ней, объединяя требуемые значения. Затем функция возвращает эту строку. Затем функция вызывается как четвертый столбец вашего запроса. Не могу помочь с синтаксисом и т. Д., Поскольку я не использую SQL-Server

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