Это неудача вашей модели. Вместо того, чтобы хранить местоположения в виде строки с разделителями, вероятно, неплохо было бы сделать таблицу размером 1-n для хранения местоположений. И на самом деле правильный «ответ» на ваш вопрос, вероятно, «перепроектирует эту часть базы данных!».
Однако, чтобы делать то, что вы хотите, вы можете делать такие вещи, как это:
USE tempdb
GO
/* udfSplit (A Fast String Splitter) **************************************************************
*
* Uses a number table to *very* quickly split the text (@text). Splits on the delimiter (@d)
* Returns Table of ([RowID], [SplitText]). Inlineable for CROSS APPLY etc.
*
* Charlie
*
*************************************************************************************************/
CREATE FUNCTION [dbo].[udfSplit] (@text NVARCHAR(4000), @d NVARCHAR(50))
RETURNS TABLE AS RETURN (
WITH numbers(n) AS (
SELECT ROW_NUMBER() OVER (ORDER BY a.[n])
FROM
(VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) AS a ([n])
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) AS b ([n])
CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) AS c ([n])
CROSS JOIN (VALUES (0), (1), (2), (3), (4)) AS d ([n])
)
SELECT
[RowID] = ROW_NUMBER() OVER (ORDER BY [n] ASC)
, [SplitText] = SUBSTRING(
@d + @text + @d
, [n] + LEN(@d)
, CHARINDEX(@d, @d + @text + @d, [n] + LEN(@d)) - [n] - LEN(@d)
)
FROM numbers AS n
WHERE [n] <= LEN(@d + @text + @d) - LEN(@d)
AND SUBSTRING(@d + @text + @d, [n], LEN(@d)) = @d
)
GO
IF OBJECT_ID('tempdb..#sample') IS NOT NULL DROP TABLE #sample
GO
CREATE TABLE #sample (
name VARCHAR(255)
, locations VARCHAR(MAX)
)
INSERT #sample (name, locations)
VALUES ('a', 'ab-cd')
, ('b', 'ab-cd-ef')
, ('c', 'gh')
, ('d', NULL)
; WITH SPLIT AS (
SELECT [name], l.*
FROM #sample AS s
OUTER APPLY dbo.[udfSplit](s.locations,'-') AS l
)
SELECT
s.name
, MAX(CASE WHEN s.rowId = 1 THEN s.SplitText ELSE '' END) AS a
, MAX(CASE WHEN s.rowId = 2 THEN s.SplitText ELSE '' END) AS b
, MAX(CASE WHEN s.rowId = 3 THEN s.SplitText ELSE '' END) AS c
, MAX(CASE WHEN s.rowId = 4 THEN s.SplitText ELSE '' END) AS d
FROM
SPLIT AS s
GROUP BY
s.name
Это, вероятно, выглядит очень сложным. Функция udfSplit - очень быстрый разделитель строк - она превращает вашу разделительную строку в таблицу, возвращающую позицию (1-4) и разделяемую строку. Если вы действительно не хотите в нее попасть, просто не волнуйтесь, как это работает. Если вы сделать хотите узнать о расщепляющих строк в БД (и вообще, почему это плохой план) - тогда читайте здесь:
http://www.sqlservercentral.com/articles/Tally+Table/72993/
Остальная часть кода составляет образец таблицы и затем делает выбор на нем, чтобы получить вывод, который вы хотели:
(4 row(s) affected)
name a b c d
-------------------- ----- ----- ----- -----
a ab cd
b ab cd ef
c gh
d
МАХ (СЛУЧАЙ ....) Выражения поворотного трюк обратно в SQL SERVER 2000 земли. Я никогда не видела оператора PIVOT.
SQL Скрипки: http://sqlfiddle.com/#!3/80f74/1
Это было бы гораздо лучше разрешено в обратном направлении. Имейте 4 столбца в таблице и столбец view/compute, чтобы отобразить 4 объединенную в виде строки с разделителями. – GarethD
Мне удалось решить мою проблему, используя функцию, найденную здесь: http://www.itdeveloperzone.com/2012/03/find-nth-occurrence-of-character-sql.html вместе с некоторой логикой случая в коде SQL который создал мое мнение. – dspencer