दो संबंधित "कई" तालिकाओं वाली तालिका के परिणामों को कैसे समतल किया जाए?


9

मैंने अपने डेटाबेस में कुछ तालिकाओं को और अधिक लचीला बनाने के लिए पुनर्गठित किया है, लेकिन मुझे यकीन नहीं है कि उनसे सार्थक डेटा निकालने के लिए एसक्यूएल कैसे लिखना है।

मेरे पास निम्न तालिकाएँ हैं (कुछ स्पष्ट उदाहरण के लिए संक्षिप्त रूप में):

CREATE TABLE Loans(
    Id int,
    SchemaId int,
    LoanNumber nvarchar(100)
);

CREATE TABLE SchemaFields(
    Id int,
    SchemaId int,
    FieldName nvarchar(255)
);

CREATE TABLE LoanFields(
    Id int,
    LoanId int,
    SchemaFieldId int,
    FieldValue nvarchar(4000)
);

निम्नलिखित डेटा के साथ:

INSERT INTO Loans (Id, SchemaId, LoanNumber) VALUES (1, 1, 'ABC123');

INSERT INTO SchemaFields (Id, SchemaId, FieldName) VALUES (1, 1, 'First Name');
INSERT INTO SchemaFields (Id, SchemaId, FieldName) VALUES (2, 1, 'Last Name');

INSERT INTO LoanFields (Id, LoanId, SchemaFieldId, FieldValue) VALUES (1, 1, 1, 'John');
INSERT INTO LoanFields (Id, LoanId, SchemaFieldId, FieldValue) VALUES (2, 1, 2, 'Doe');

उद्देश्य एक ऐसी क्वेरी प्राप्त करना है जो अपने सभी क्षेत्रों के साथ ऋण के लिए फ्लैट है। (वास्तविक दुनिया में एक ही स्कीमा के लिए 20-30 क्षेत्रों के बीच होने की संभावना होगी, लेकिन हमारे पास उदाहरण में 2 हैं):

LoanNumber   First Name    Last Name
----------   -----------   ----------
ABC123       John          Doe

मैं 'फर्स्ट नेम' और 'लास्ट नेम' का संदर्भ देने वाली धुरी का उपयोग नहीं कर सकता क्योंकि मुझे पता नहीं होगा कि वास्तव में क्या होगा।

मेरे पास यहां पहले से ही स्कीमा के साथ SQL फिडेल है।

मैं वांछित परिणाम कैसे प्राप्त कर सकता हूं?

जवाबों:


7

यह PIVOT फ़ंक्शन का उपयोग करके किया जा सकता है , लेकिन चूंकि यह लगता है कि आप स्कीमा पर आधारित क्वेरी को बदलना चाहते हैं, तो आप डायनेमिक SQL का उपयोग करना चाहेंगे।

यदि आपके पास मूल्यों की एक ज्ञात संख्या थी या किसी विशिष्ट स्कीमा के लिए कॉलम पता था, तो आप क्वेरी को हार्ड-कोड कर सकते थे। एक स्थिर क्वेरी होगी:

select loannumber,
  [First Name], 
  [Middle Name], 
  [Last Name]
from
(
  select 
    l.loannumber,
    sf.fieldname,
    lf.fieldvalue
  from loans l
  left join loanfields lf
    on l.id = lf.loanid
  left join schemafields sf
    on lf.schemafieldid = sf.id
    and l.schemaid = sf.schemaid
) src
pivot
(
  max(fieldvalue)
  for fieldname in ([First Name], [Middle Name], [Last Name])
)piv;

SQL फिडेल को डेमो के साथ देखें ।

यदि आपके पास कोई अज्ञात नंबर था या आप चाहते हैं कि स्तंभ SchemaIdउस प्रक्रिया के आधार पर परिवर्तित हो जाएं, जो आप एक प्रक्रिया से गुजर रहे हैं, तो आप SQL स्ट्रिंग उत्पन्न करने के लिए गतिशील SQL का उपयोग करेंगे:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX),
    @schemaId int = 1

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(FieldName) 
                    from SchemaFields 
                    where schemaid = @schemaid
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT loannumber,' + @cols + ' 
            from 
            (
              select 
                l.loannumber,
                sf.fieldname,
                lf.fieldvalue
              from loans l
              left join loanfields lf
                on l.id = lf.loanid
              left join schemafields sf
                on lf.schemafieldid = sf.id
                and l.schemaid = sf.schemaid
              where sf.schemaid = '+cast(@schemaid as varchar(10))+'
            ) x
            pivot 
            (
                max(fieldvalue)
                for fieldname in (' + @cols + ')
            ) p '

execute(@query);

SQL फिडेल को डेमो के साथ देखें । ये दोनों प्रश्न परिणाम उत्पन्न करेंगे:

| LOANNUMBER | FIRST NAME | LAST NAME | MIDDLE NAME |
-----------------------------------------------------
|     ABC123 |       John |       Doe |      (null) |
|     XYZ789 |    Charles |     Smith |         Lee |

3

आप इस पैटर्न का उपयोग कर सकते हैं। अधिक स्कीमा फ़ील्ड के लिए, सभी स्कीमा फ़ील्ड नामों के साथ 2 लास्ट लाइन पर विस्तार करें।

select *
  from (
    select l.LoanNumber, s.FieldName, f.FieldValue
      from Loans l
      join Schemafields s on s.SchemaId = l.SchemaId
      join LoanFields f on f.LoanId = l.Id and f.SchemaFieldId = s.Id) p
pivot (
    max(FieldValue) for FieldName in ([First Name], [Last Name])
    ) v;

यदि प्रकार के SchemaId = 1लिए फ़ील्ड का प्रतिनिधित्व करता है Loan, तो आप schema field namesनीचे की तरह कुछ का उपयोग करने की पूरी सूची को गतिशील रूप से भी उत्पन्न कर सकते हैं।

declare @sql nvarchar(max) =
    stuff((select ',' + quotename(FieldName)
      from SchemaFields
     where SchemaId = 1
       for xml path(''), type).value('/','nvarchar(max)'),1,1,'');
select @sql = '
select *
  from (
    select l.LoanNumber, s.FieldName, f.FieldValue
      from Loans l
      join Schemafields s on s.SchemaId = l.SchemaId
      join LoanFields f on f.LoanId = l.Id and f.SchemaFieldId = s.Id) p
pivot (
    max(FieldValue) for FieldName in (' + @sql + ')
    ) v';
exec (@sql);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.