如何展平具有两个相关“许多”表的表的结果?

Sai*_*udo 10 pivot t-sql sql-server-2012

我重新组织了数据库中的一些表以使其更加灵活,但我不确定如何编写 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)
);
Run Code Online (Sandbox Code Playgroud)

使用以下数据:

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');
Run Code Online (Sandbox Code Playgroud)

目标是获得一个查询,该查询对于所有字段的贷款都是平坦的。(在现实世界中,同一个模式可能有 20-30 个字段,但我们在示例中只有 2 个):

LoanNumber   First Name    Last Name
----------   -----------   ----------
ABC123       John          Doe
Run Code Online (Sandbox Code Playgroud)

我不能使用引用“名字”和“姓氏”的数据透视表,因为我不知道那里实际存在什么。

这里有一个SQL Fiddle,其中的架构已经就位。

我怎样才能得到想要的结果?

Tar*_*ryn 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;
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo

如果您有一个未知数字,或者您希望根据SchemaId您传递给过程的a 来更改列,那么您将使用动态 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);
Run Code Online (Sandbox Code Playgroud)

请参阅SQL Fiddle with Demo。这两个查询都会生成结果:

| LOANNUMBER | FIRST NAME | LAST NAME | MIDDLE NAME |
-----------------------------------------------------
|     ABC123 |       John |       Doe |      (null) |
|     XYZ789 |    Charles |     Smith |         Lee |
Run Code Online (Sandbox Code Playgroud)