Làm thế nào để làm phẳng kết quả của một bảng với hai bảng nhiều điểm có liên quan?


9

Tôi đã sắp xếp lại một số bảng trong cơ sở dữ liệu của mình để linh hoạt hơn nhưng tôi không thực sự chắc chắn làm thế nào để viết SQL để trích xuất dữ liệu có ý nghĩa từ chúng.

Tôi có các bảng sau (viết tắt một chút cho một ví dụ rõ ràng hơn):

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)
);

Với dữ liệu sau:

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');

Mục tiêu là để có được một truy vấn không thay đổi cho một khoản vay với tất cả các lĩnh vực của nó. (Trong thế giới thực, có thể sẽ có từ 20-30 trường cho cùng một lược đồ, nhưng chúng ta chỉ có 2 trong ví dụ):

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

Tôi không thể sử dụng trục xoay tham chiếu 'Tên' và 'Họ' vì tôi không biết cái gì sẽ thực sự ở đó.

Tôi có một SQL Fiddle ở đây với lược đồ đã có sẵn.

Làm thế nào tôi có thể nhận được kết quả mong muốn?

Câu trả lời:


7

Điều này có thể được thực hiện bằng cách sử dụng hàm PIVOT , nhưng vì có vẻ như bạn muốn thay đổi truy vấn dựa trên lược đồ, nên bạn sẽ muốn sử dụng SQL động.

Nếu bạn đã có một số giá trị đã biết hoặc biết các cột cho một lược đồ cụ thể, thì bạn có thể mã hóa truy vấn. Một truy vấn tĩnh sẽ là:

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;

Xem SQL Fiddle với Demo .

Nếu bạn có một số chưa biết hoặc bạn muốn các cột thay đổi dựa trên số SchemaIdmà bạn đang chuyển vào một thủ tục, thì bạn sẽ sử dụng SQL động để tạo chuỗi 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);

Xem SQL Fiddle với Demo . Cả hai truy vấn này sẽ tạo ra kết quả:

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

3

Bạn có thể sử dụng mô hình này. Đối với nhiều trường lược đồ hơn, chỉ cần mở rộng trên dòng thứ 2 đến dòng cuối cùng với tất cả các tên trường lược đồ.

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;

Nếu SchemaId = 1đại diện cho các trường cho Loanloại, thì bạn cũng có thể tự động tạo danh sách đầy đủ về schema field namesviệc sử dụng một cái gì đó như dưới đây.

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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.