2010-11-22 32 views
9

Bunu nasıl başaracağımı söyleyen var mı? Masamdaki bir sütun, bazı durumlarda virgülle ayrılmış değerler içerir. Eğer varsa, bu değerler için yeni satırlar oluşturmalıyım. Ayrıca, örnek olarak, bir tablo 1 satır ve 4 sütun Col1 içerir. Üste | Col2 | Col3 | Aşağıdaki değerlerle Col4 A | B | C | Sırasıyla 1,2,3. Yani, Col4 '1,2,3' dizesini içerir ve ben virgülle ayrılmış değerleri kırmalı ve bunları kendi satırlarına yerleştirmeliyim, böylece tablo 1 satır ve 1 2 ve 3'ün kendi satırlarının olduğu 1 sıra içerecektir. Col4'te.Bir sütunu birden çok satıra ayırma

+0

SQL Server'da bu mu? Hangi sürümü lütfen? –

+1

Tek sütunlar içindeki virgülle ayrılmış değerler ** yanlış **. Lütfen şemayı tamir etmek için çalıştığını söyle? –

+0

Bir sütunu birden çok satıra bölen çok daha büyük bir sorununuz var. Veritabanınızda MAJOR tasarım hatası var. –

cevap

8

ben bunu düşünüyorum:

SELECT 
    T.id, RIGHT(LEFT(T.csv,Number-1), 
    CHARINDEX(',',REVERSE(LEFT(','+T.csv,Number-1)))) 
FROM 
    master..spt_values, 
    your_table T 
WHERE 
    Type = 'P' AND Number BETWEEN 1 AND LEN(T.csv)+1 
    AND 
    (SUBSTRING(T.csv,Number,1) = ',' OR SUBSTRING(T.csv,Number,1) = '') 

Kod utanmadan this site çalındı.

+0

Bazı büyük alan değerleri için işe yaramamış olmasına rağmen, yine de harika bir fikirdir (spt_values'i değiştirmek için bir geçici tablo kullanılır). – Umer

3

Bir tablo işlevi yazıp, sütununuza CROSS APPLY ile katılabilirsiniz. İşte benim versiyonum.

CREATE FUNCTION dbo.Splitter(@text nvarchar(max), @separator nvarchar(100)) 
RETURNS @result TABLE (i int, value nvarchar(max)) 
AS 
BEGIN 
    DECLARE @i int 
    DECLARE @offset int 
    SET @i = 0 

    WHILE @text IS NOT NULL 
    BEGIN 
     SET @i = @i + 1 
     SET @offset = charindex(@separator, @text) 
     INSERT @result SELECT @i, CASE WHEN @offset > 0 THEN LEFT(@text, @offset - 1) ELSE @text END 
     SET @text = CASE WHEN @offset > 0 THEN SUBSTRING(@text, @offset + LEN(@separator), LEN(@text)) END 
    END 
    RETURN 
END 
+0

Komut dosyanızı çalıştırmak, "Geçersiz nesne adı 'splitter'" hatasını üretir. Hangi ayırıcı işlevini değiştirmeyi teklif edersiniz? –

+1

İyi yakalama! –

3

Bir çok dize ayırma işlevinden biri de dışarıda çalışır. Bu, @Byron Whitlock'un answer'a benzer, ancak master..spt_values ​​kullanmak yerine bir sayı tablosu oluşturmak için bir cte kullanır. SQL Server 2005'ten itibaren.

CREATE TABLE dbo.Table1 
(
    Col1  CHAR(1), 
    Col2  CHAR(1), 
    Col3  CHAR(1), 
    Col4  VARCHAR(50) 
) 
GO 

INSERT INTO dbo.Table1 VALUES ('A','B','C','1,2,3') 
GO 

SELECT * FROM dbo.Table1; 
GO 

WITH 
L0 AS(SELECT 1 AS c UNION ALL SELECT 1), 
L1 AS(SELECT 1 AS c FROM L0 AS A, L0 AS B), 
L2 AS(SELECT 1 AS c FROM L1 AS A, L1 AS B), 
L3 AS(SELECT 1 AS c FROM L2 AS A, L2 AS B), 
Numbers AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L3) 
SELECT Col1, Col2, Col3,   
     LTRIM(RTRIM(SUBSTRING(valueTable.Col4, nums.n, charindex(N',', valueTable.Col4 + N',', nums.n) - nums.n))) AS [Value] 
FROM Numbers AS nums INNER JOIN dbo.Table1 AS valueTable ON nums.n <= CONVERT(int, LEN(valueTable.Col4)) AND SUBSTRING(N',' + valueTable.Col4, n, 1) = N',' 
+0

+1 wow oluşturmak için alter değiştirdim, runnable kodu için teşekkürler. Ben de en zarif çözüm olarak beğendim –

+0

Bir kenar çubuğunun bir parçası olarak, aslında çok fazla, daha yavaş olacak bir tekrarlayıcı CTE değil. –

+0

@Jeff Moden İyi nokta, buna göre değiştirildi –

0

Bunun eski bir yayın olduğunu biliyorum ancak bir güncelleştirme ekleyeceğimi düşündüm. Tally Table ve cteTally tablo tabanlı bölücülerin hepsi büyük bir soruna sahiptir. Birleştirilmiş sınırlayıcılar kullanırlar ve elemanlar genişledikçe ve ipler daha uzun hale geldiklerinde hızlarını öldürürler.

Bu sorunu çözdüm ve URL'yi takip edende bulabileceğiniz bir makale yazdım. http://www.sqlservercentral.com/articles/Tally+Table/72993/

Ben de "Peter" adlı bir adam (makale için tartışmaya) bile bu kodu bir iyileştirme yaptığını anlatacağım. Makale hala ilginç ve ekleri ertesi gün veya iki gün içinde Peter'ın geliştirmeleri ile güncelleyeceğiz. Büyük geliştirmemle Peter'in yaptığı tweek arasında, VARCHAR'ı bölmek için daha hızlı bir T-SQL-Only çözümü bulacağına inanmıyorum (8000). Aynı zamanda VARCHAR (MAX) için bölücülerin sorununu da çözdüm ve bunun için de bir makale yazdım.

İlgili konular