วิธีการแผ่ผลของตารางที่มีสองตารางที่ "เกี่ยวข้อง" อย่างเกี่ยวข้องได้อย่างไร


9

ฉันได้จัดตารางบางส่วนในฐานข้อมูลของฉันให้มีความยืดหยุ่นมากขึ้น แต่ฉันไม่แน่ใจว่าจะเขียน SQL อย่างไรเพื่อดึงข้อมูลที่มีความหมายออกมา

ฉันมีตารางต่อไปนี้ (ค่อนข้างยากสำหรับตัวอย่างที่ชัดเจน):

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 Fiddle ที่นี่พร้อมกับสคีมาอยู่แล้ว

ฉันจะได้รับผลลัพธ์ที่ต้องการได้อย่างไร

คำตอบ:


7

สิ่งนี้สามารถทำได้โดยใช้ฟังก์ชั่นPIVOTแต่ดูเหมือนว่าคุณต้องการเปลี่ยนแบบสอบถามตาม schemaId ดังนั้นคุณจะต้องใช้ SQL แบบไดนามิก

หากคุณมีจำนวนค่าที่รู้จักหรือรู้คอลัมน์สำหรับ schemaID ที่เฉพาะเจาะจงคุณสามารถเข้ารหัสแบบสอบถามอย่างหนัก แบบสอบถามแบบคงที่จะเป็น:

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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.