Как вернуть значения столбца через запятую, не просматривая набор результатов - PullRequest
0 голосов
/ 28 сентября 2018

Допустим, у меня есть эта 2 таблица

+----+---------+       +----+-----------+----------------+
| Id | Country |       | Id | CountryId | City           |
+----+---------+       +----+-----------+----------------+
| 1  | USA     |       | 1  |   1       | Washington, DC |
+----+---------+       +----+-----------+----------------+
| 2  | Canada  |       | 2  |   2       | Ottawa         |
+----+---------+       +----+-----------+----------------+
                       | 3  |   1       | New York       |
                       +----+-----------+----------------+
                       | 4  |   1       | Baltimore      |
                       +----+-----------+----------------+

Мне нужно получить такой результат, как:

Id | Country | Cities
---+---------+--------------------------------------
1  | USA     | Washington, DC, New York, Baltimore
---+------------------------------------------------
2  | Canada  | Ottawa

Пока я перебираю результат левой таблицы, как этот:

DECLARE @table 
(
   Id INT IDENTITY(1, 1),
   CountryId INT,
   City VARCHAR(50)
 )

DECLARE @tableString
(
   Id INT IDENTITY(1, 1),
   CountryId INT,
   Cities VARCHAR(100)
)

INSERT INTO @table
SELECT Id, City
FROM tblCountries

DECLARE @city VARCHAR(50)
DECLARE @id INT
DECLARE @count INT
DECLARE @i INT = 1
SELECT @count = COUNT(*) FROM @table

WHILE (@i <= @count)
  BEGIN
    SELECT @Id = Id, @city = City FROM @table WHERE Id = @i
    IF(EXISTS(SELECT * FROM @tableString WHERE CountryId = @Id))  
      BEGIN
         UPDATE @tableString SET Cities = Cities + ', ' + @city WHERE Id = @Id
      END
    ELSE
      BEGIN
        INSERT INTO @tableString (CountryId, city) VALUES (@Id, @city)
      END
    SET @i = @i + 1
  END

  SELECT tc.Id, tc.Country, ts.Cities
  FROM tblCountries tc
  LEFT JOIN @tableString ts
  ON tc.Id = ts.CountryId

Меня беспокоит то, что со всеми этими циклами в TSQL это может привести к снижению производительности.Даже с меньшим, это кажется медленным.Есть ли лучший способ объединить эти строки без циклического прохождения набора данных, как если бы я работал в C #.Спасибо за помощь

1 Ответ

0 голосов
/ 01 октября 2018

На это отвечали много раз, но у меня такое ощущение, что какое-то объяснение может помочь вам ...

... я что-то упустил?Похоже, что это связано с XML

Необходимая функциональность STRING_AGG () была введена в SQL-Server 2017. Другое направление STRING_SPLIT () пришлос v2016.

Но многие люди все еще используют более старые версии (и будут делать это годами), поэтому нам нужны обходные пути.Были подходы с циклами, плохие и медленные ... И вы могли бы использовать рекурсивные CTE.И - вот в чем дело!- мы можем использовать некоторые возможности XML для решения этой проблемы.

Попробуйте это:

DECLARE @xml XML=
N'<root>
    <element>text1</element>
    <element>text2</element>
    <element>text3</element>
</root>';

- Запрос вернет первый <element> ниже <root> и вернет text1 .

SELECT @xml.value(N'(/root/element)[1]','nvarchar(max)');

- Но теперь попробуйте это:

SELECT @xml.value(N'(/root)[1]','nvarchar(max)') 

Результат будет text1text2text3 .
Причина этого:Если вы вызовете .value() для элемента без подробной спецификации , что вы хотите прочитать, вы получите весь элемент обратно.Найти подробности здесь .

Теперь представьте XML-код, подобный этому

DECLARE @xml2 XML=
N'<root>
    <element>, text1</element>
    <element>, text2</element>
    <element>, text3</element>
</root>';

С тем же запросом, что и выше, вы получите , text1, text2, text3.Осталось только отрезать запятую и пробел.Это делается - в большинстве случаев - с помощью STUFF () .

Таким образом, задача состоит в том, чтобы создать этот XML.И это то, что вы найдете в связанных примерах.

Общий пример таков: прочитайте все таблицы и перечислите их столбцы в виде CSV-списка:

SELECT TOP 10
       TABLE_NAME
      ,STUFF(
       (SELECT ',' + c.COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS c 
        WHERE c.TABLE_SCHEMA=t.TABLE_SCHEMA AND c.TABLE_NAME=t.TABLE_NAME
        ORDER BY c.COLUMN_NAME
        FOR XML PATH('')
       ),1,1,'') AS AllTableColumns
FROM INFORMATION_SCHEMA.TABLES t
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...