2011-09-07 13 views
9

कुंजी-मूल्य जोड़ी परिणाम सेट प्राप्त करने का सबसे अच्छा तरीका क्या है जो पंक्ति में कॉलम-मान का प्रतिनिधित्व करता है?एक कुंजी-पंक्ति जोड़ी तालिका में 1 पंक्ति तालिका का फ़्लैटनिंग

केवल 1 पंक्ति के साथ निम्न तालिका किसी दिए गए


Column1 Column2 Column3... 
Value1 Value2 Value3 

मैं इसे क्वेरी और एक अन्य तालिका बी में सम्मिलित करना चाहते हैं:


Key Value 
Column1    Value1 
Column2    Value2 
Column3    Value3 

तालिका एक में कॉलम का एक सेट में ज्ञात नहीं है अग्रिम।

नोट:


    DECLARE @sql nvarchar(max) 
    SET @sql = (SELECT STUFF((SELECT ',' + column_name 
           FROM INFORMATION_SCHEMA.COLUMNS 
           WHERE table_name='TableA' 
           ORDER BY column_name FOR XML PATH('')), 1, 1, '')) 
    SET @sql = 'SELECT ' + @sql + ' FROM TableA' 
    EXEC(@sql) 
+3

यह एक 'UNPIVOT' नहीं एक' PIVOT' है लेकिन आप अभी भी गतिशील एसक्यूएल की आवश्यकता होगी। मार्टिन की टिप्पणी के लिए –

+0

+1। जैसा कि आप अनपढ़ किए गए कॉलम नहीं जानते हैं, आपको डायनामिक एसक्यूएल की आवश्यकता है। – MatBailie

+0

@Aaron - बस एक टाइपो, अब तय – kateroh

उत्तर

18

एक संस्करण है जहाँ कोई गतिशील शामिल है। यदि आपके पास कॉलम नाम हैं जो XML में तत्व नामों के रूप में उपयोग करने के लिए अमान्य हैं तो यह असफल हो जाएगा।

select T2.N.value('local-name(.)', 'nvarchar(128)') as [Key], 
     T2.N.value('text()[1]', 'nvarchar(max)') as Value 
from (select * 
     from TableA 
     for xml path(''), type) as T1(X) 
    cross apply T1.X.nodes('/*') as T2(N) 

एक काम कर नमूना:

declare @T table 
(
    Column1 varchar(10), 
    Column2 varchar(10), 
    Column3 varchar(10) 
) 

insert into @T values('V1','V2','V3') 

select T2.N.value('local-name(.)', 'nvarchar(128)') as [Key], 
     T2.N.value('text()[1]', 'nvarchar(max)') as Value 
from (select * 
     from @T 
     for xml path(''), type) as T1(X) 
    cross apply T1.X.nodes('/*') as T2(N) 

परिणाम:

Key     Value 
-------------------- ----- 
Column1    V1 
Column2    V2 
Column3    V3 

अद्यतन

एक से अधिक टेबल के साथ एक प्रश्न के लिए आप for xml auto का उपयोग तालिका प्राप्त करने के लिए कर सकता है एक्सएमएल में नाम। नोट, यदि आप क्वेरी में तालिका नामों के लिए उपनाम का उपयोग करते हैं तो आपको इसके बजाय उपनाम प्राप्त होगा।

select X2.N.value('local-name(..)', 'nvarchar(128)') as TableName, 
     X2.N.value('local-name(.)', 'nvarchar(128)') as [Key], 
     X2.N.value('text()[1]', 'nvarchar(max)') as Value 
from (
    -- Your query starts here 
    select T1.T1ID, 
      T1.T1Col, 
      T2.T2ID, 
      T2.T2Col 
    from T1 
     inner join T2 
     on T1.T1ID = T2.T1ID 
    -- Your query ends here 
    for xml auto, elements, type  
    ) as X1(X) 
    cross apply X1.X.nodes('//*[text()]') as X2(N) 

SQL Fiddle

+0

अच्छा ................! –

+0

स्वीकार करना है, यह एक दिलचस्प दृष्टिकोण है। – 8kb

+0

स्थानीय-नाम (।) ने स्तंभ नामों के लिए चाल की है। अच्छा धन्यवाद! – kateroh

3

शायद आप इस और अधिक जटिल की तुलना में यह करने की जरूरत है कर रहे हैं: मैं इस तरह कुछ करने के लिए XML और धुरी सुविधाओं के साथ-साथ गतिशील एसक्यूएल के लिए देख रहा था। आंशिक रूप से क्योंकि मैं अपने छोटे दिमाग को PIVOT/UNPIVOT/जो भी संयोजन और गतिशील एसक्यूएल "लाल रंग का समुद्र" की संख्या के चारों ओर खींचने के लिए जरूरी नहीं था। चूंकि आप जानते हैं कि तालिका में एक पंक्ति है, प्रत्येक कॉलम के लिए मान खींचना UNION एड क्वेरी के सेट के हिस्से के रूप में केवल एक सबक्वायरी हो सकता है।

DECLARE @sql NVARCHAR(MAX) = N'INSERT dbo.B([Key], Value) ' 

SELECT @sql += CHAR(13) + CHAR(10) 
     + ' SELECT [Key] = ''' + REPLACE(name, '''', '''''') + ''', 
     Value = (SELECT ' + QUOTENAME(name) + ' FROM dbo.A) UNION ALL' 
FROM sys.columns 
WHERE [object_id] = OBJECT_ID('dbo.A'); 

SET @sql = LEFT(@sql, LEN(@sql)-9) + ';'; 

PRINT @sql; 
-- EXEC sp_executesql @sql; 

परिणाम (मैं केवल 4 कॉलम बनाया है, लेकिन यह किसी भी संख्या के लिए काम करेगा): दुनिया में

INSERT dbo.B([Key], Value) 
SELECT [Key] = 'Column1', 
     Value = (SELECT [Column1] FROM dbo.A) UNION ALL 
SELECT [Key] = 'Column2', 
     Value = (SELECT [Column2] FROM dbo.A) UNION ALL 
SELECT [Key] = 'Column3', 
     Value = (SELECT [Column3] FROM dbo.A) UNION ALL 
SELECT [Key] = 'Column4', 
     Value = (SELECT [Column4] FROM dbo.A); 

सबसे कुशल बात? शायद नहीं। लेकिन फिर, एक पंक्ति वाली तालिका के लिए, और उम्मीद है कि एक बंद कार्य, मुझे लगता है कि यह ठीक काम करेगा। केवल उन स्तंभ नामों के लिए देखें जिनमें apostrophes शामिल हैं, यदि आप उन चीज़ों को अपनी दुकान में अनुमति देते हैं ...

संपादित करें क्षमा करें, इसे इस तरह से नहीं छोड़ सका। अब यह कॉलम नामों और अन्य उप-इष्टतम नामकरण विकल्पों में apostrophes को संभालेगा।

6

मुझे लगता है कि आप वहां आधा रास्ते हैं। बस मार्टिन के रूप में UNPIVOT और dynamic SQL का उपयोग की सिफारिश की:

CREATE TABLE TableA (
    Code VARCHAR(10), 
    Name VARCHAR(10), 
    Details VARCHAR(10) 
) 

INSERT TableA VALUES ('Foo', 'Bar', 'Baz') 
GO 

DECLARE @sql nvarchar(max) 
SET @sql = (SELECT STUFF((SELECT ',' + column_name 
          FROM INFORMATION_SCHEMA.COLUMNS 
          WHERE table_name='TableA' 
          ORDER BY ordinal_position FOR XML PATH('')), 1, 1, '')) 

SET @sql = N'SELECT [Key], Val FROM (SELECT ' + @sql + ' FROM TableA) x ' 
+ 'UNPIVOT (Val FOR [Key] IN (' + @sql + ')) AS unpiv' 
EXEC (@sql) 

परिणाम:

Key   Val 
------------ ------------ 
Code   Foo 
Name   Bar 
Details  Baz 

वहाँ एक चेतावनी है निश्चित रूप से। उपर्युक्त कोड के लिए काम करने के लिए आपके सभी कॉलमों को एक ही डेटा प्रकार होना आवश्यक होगा। यदि वे नहीं हैं, तो आपको यह त्रुटि मिल जाएगी:

Msg 8167, Level 16, State 1, Line 1 
The type of column "Col" conflicts with the type of 
other columns specified in the UNPIVOT list. 

इसके आसपास जाने के लिए, आपको दो कॉलम स्ट्रिंग स्टेटमेंट बनाने होंगे। एक कॉलम प्राप्त करने के लिए और एक को अपने वैल कॉलम के लिए डेटा प्रकार के रूप में सभी को कास्ट करने के लिए।

कई कॉलम प्रकार के लिए:

CREATE TABLE TableA (
    Code INT, 
    Name VARCHAR(10), 
    Details VARCHAR(10) 
) 

INSERT TableA VALUES (1, 'Foo', 'Baf') 
GO 

DECLARE 
    @sql nvarchar(max), 
    @cols nvarchar(max), 
    @conv nvarchar(max) 

SET @cols = (SELECT STUFF((SELECT ',' + column_name 
          FROM INFORMATION_SCHEMA.COLUMNS 
          WHERE table_name='TableA' 
          ORDER BY ordinal_position FOR XML PATH('')), 1, 1, '')) 

SET @conv = (SELECT STUFF((SELECT ', CONVERT(VARCHAR(50), ' 
          + column_name + ') AS ' + column_name 
          FROM INFORMATION_SCHEMA.COLUMNS 
          WHERE table_name='TableA' 
          ORDER BY ordinal_position FOR XML PATH('')), 1, 1, '')) 


SET @sql = N'SELECT [Key], Val FROM (SELECT ' + @conv + ' FROM TableA) x ' 
+ 'UNPIVOT (Val FOR [Key] IN (' + @cols + ')) AS unpiv' 
EXEC (@sql) 
संबंधित मुद्दे