अंतिम संस्करण (मुझे आशा है):
चूंकि एसक्यूएल सर्वर 2008 कुल कार्यों के ओवर क्लॉज में ऑर्डर का समर्थन नहीं करता है, इसलिए मैंने sum
के बजाय पंक्ति अनुक्रमणिका जोड़ने के लिए एक और सीटीई जोड़ा है मैंने पिछले संस्करण में उपयोग किया है:
;WITH cteAllRows as
(
SELECT Item,
ItemIndex,
CASE WHEN ISNUMERIC(Item) = 0 THEN 'String'
WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0 THEN 'Double'
WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0 THEN 'Integer'
END As DataType
FROM dbo.SplitStrings_Numbers(@string, ',')
), cteAll as
(
SELECT Item,
DataType,
ItemIndex,
(
SELECT COUNT(*)
FROM cteAllRows tInner
WHERE tInner.DataType = 'String'
AND tInner.ItemIndex <= tOuter.ItemIndex
) As RowIndex
FROM cteAllRows tOuter
)
बाकी सब पिछले संस्करण जैसा ही है।
अपडेट करें
पहली चीज जो मैंने की है वह है स्ट्रिंग स्प्लिट फंक्शन को टैली टेबल के आधार पर एक फंक्शन में बदलना, ताकि मैं इसमें आसानी से रो नंबर जोड़ सकूं। इसलिए, यदि आपके पास पहले से कोई मिलान तालिका नहीं है, एक बनाएं .अगर आप अपने आप से पूछ रहे हैं कि टैली टेबल क्या है और आपको इसकी आवश्यकता क्यों है, जेफ मोडेन का यह लेख पढ़ें :
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Tally
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Tally ADD CONSTRAINT PK_NumbersTest PRIMARY KEY CLUSTERED (Number)
GO
फिर, टैली टेबल के आधार पर स्ट्रिंग स्प्लिट फंक्शन बनाएं (हारून के लेख से लिया गया लेकिन पंक्ति इंडेक्स कॉलम जोड़ा गया):
CREATE FUNCTION dbo.SplitStrings_Numbers
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = SUBSTRING(@List, Number, CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number),
ROW_NUMBER() OVER (ORDER BY Number) As ItemIndex
FROM dbo.Tally
WHERE Number <= CONVERT(INT, LEN(@List))
AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
);
GO
अब, मैंने जिस ट्रिक का उपयोग किया है, वह पिछले वाले की तरह ही है, केवल अब मैंने पहले cte में एक नया कॉलम जोड़ा है जिसे मैंने RowIndex कहा है, जो मूल रूप से पंक्ति के आधार पर स्ट्रिंग्स की गिनती का कुल योग है। सभी पंक्तियों की अनुक्रमणिका:
SELECT Item,
CASE WHEN ISNUMERIC(Item) = 0 THEN 'String'
WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0 THEN 'Double'
WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0 THEN 'Integer'
END As DataType,
SUM(CASE WHEN ISNUMERIC(Item) = 0 THEN 1 END) OVER(ORDER BY ItemIndex) As RowIndex
FROM dbo.SplitStrings_Numbers(@string, ',')
इसने मुझे यह परिणाम दिया:
Item DataType RowIndex
---------- -------- -----------
ddd String 1
1.5 Double 1
1 Integer 1
eee String 2
2.3 Double 2
0 Integer 2
fff String 3
1.2 Double 3
ggg String 4
6.123 Double 4
1 Integer 4
जैसा कि आप देख सकते हैं, मेरे पास अब प्रत्येक पंक्ति के लिए एक संख्या है, इसलिए अब से यह आसान है:
;WITH cteAll as
(
SELECT Item,
CASE WHEN ISNUMERIC(Item) = 0 THEN 'String'
WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0 THEN 'Double'
WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0 THEN 'Integer'
END As DataType,
SUM(CASE WHEN ISNUMERIC(Item) = 0 THEN 1 END) OVER(ORDER BY ItemIndex) As RowIndex
FROM dbo.SplitStrings_Numbers(@string, ',')
), cteString AS
(
SELECT Item, RowIndex
FROM cteAll
WHERE DataType = 'String'
), cteDouble AS
(
SELECT Item, RowIndex
FROM cteAll
WHERE DataType = 'Double'
), cteInteger AS
(
SELECT Item, RowIndex
FROM cteAll
WHERE DataType = 'Integer'
)
SELECT T1.Item As [String],
T2.Item As [Double],
T3.Item As [Integer]
FROM dbo.Tally
LEFT JOIN cteString T1 ON T1.RowIndex = Number
LEFT JOIN cteDouble T2 ON t2.RowIndex = Number
LEFT JOIN cteInteger T3 ON t3.RowIndex = Number
WHERE COALESCE(T1.Item, T2.Item, T3.Item) IS NOT NULL
इसने मुझे यह परिणाम दिया:
String Double Integer
---------- ---------- ----------
ddd 1.5 1
eee 2.3 0
fff 1.2 NULL
ggg 6.123 1
जैसा कि आप देख सकते हैं, आइटम अब स्ट्रिंग में मूल क्रम के अनुसार क्रमबद्ध हैं। चुनौती के लिए धन्यवाद, यह कुछ समय हो गया है जब से मेरे पास एक अच्छा है :-)
पहला प्रयास
ठीक है, पहले आपको उस स्ट्रिंग को एक टेबल में विभाजित करना होगा। ऐसा करने के लिए आपको उपयोगकर्ता परिभाषित फ़ंक्शन का उपयोग करना चाहिए। आप हारून बर्ट्रेंड के स्प्लिट स्ट्रिंग्स में से अपने लिए सबसे उपयुक्त चुन सकते हैं। सही तरीका - या अगला सबसे अच्छा तरीका लेख।
इस प्रदर्शन के लिए मैंने SplitStrings_XML
. का उपयोग करना चुना है ।
तो सबसे पहले, फंक्शन बनाएं:
CREATE FUNCTION dbo.SplitStrings_XML
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(@List, @Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
अब, वेरिएबल घोषित करें और इनिशियलाइज़ करें:
declare @string nvarchar(max) = 'ddd,1.5,1,eee,2.3,0,fff,1.2,ggg,6.123,1'
फिर, 4 सामान्य तालिका भाव
बनाएं - सभी वस्तुओं के लिए एक, स्ट्रिंग्स के लिए एक, डबल्स के लिए एक और पूर्णांकों के लिए एक। row_number()
के इस्तेमाल पर ध्यान दें
फ़ंक्शन - इसका उपयोग बाद में सभी परिणामों को एक साथ जोड़ने के लिए किया जाएगा:
;WITH AllItems as
(
SELECT Item, ROW_NUMBER() OVER(ORDER BY (select null)) as rn
FROM dbo.SplitStrings_XML(@string, ',')
)
, Strings as
(
SELECT Item as StringItem, ROW_NUMBER() OVER(ORDER BY (select null)) as rn
FROM dbo.SplitStrings_XML(@string, ',')
WHERE ISNUMERIC(Item) = 0
), Doubles as
(
SELECT Item as DoubleItem, ROW_NUMBER() OVER(ORDER BY (select null)) as rn
FROM dbo.SplitStrings_XML(@string, ',')
WHERE ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0
), Integers as
(
SELECT Item as IntegerItem, ROW_NUMBER() OVER(ORDER BY (select null)) as rn
FROM dbo.SplitStrings_XML(@string, ',')
WHERE ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0
)
फिर, इन सभी सामान्य तालिका अभिव्यक्तियों में शामिल होने से चुनें। COALESCE
के इस्तेमाल पर ध्यान दें
फ़ंक्शन में केवल उन पंक्तियों को वापस करने के लिए बनाया गया है जहां कम से कम एक मान मौजूद है:
SELECT StringItem, DoubleItem, IntegerItem
FROM AllItems A
LEFT JOIN Strings S ON A.rn = S.rn
LEFT JOIN Doubles D ON A.rn = D.rn
LEFT JOIN Integers I ON A.rn = I.rn
WHERE COALESCE(StringItem, DoubleItem, IntegerItem) IS NOT NULL
परिणाम:
StringItem DoubleItem IntegerItem
---------- ---------- -----------
ddd 1.5 1
eee 2.3 0
fff 1.2 1
ggg 6.123 NULL