Bir tablonun sonuçlarını iki ilişkili “çok” tablo ile nasıl düzleştirebilirim?


9

Veritabanımdaki bazı tabloları daha esnek olacak şekilde yeniden düzenledim, ancak onlardan anlamlı veriler çıkarmak için SQL yazmayı gerçekten bilmiyorum.

Aşağıdaki tablolar var (biraz daha net bir örnek için kısaltılmış):

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

Aşağıdaki verilerle:

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

Amaç, tüm alanları ile bir kredi için düz bir sorgu elde etmektir. (Gerçek dünyada aynı şema için muhtemelen 20-30 alan olacak, ancak örnekte sadece 2 tane var):

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

'Ad' ve 'Soyadı' ile ilgili bir pivot kullanamıyorum çünkü orada ne olacağı hakkında hiçbir fikrim yok.

Burada zaten bir şema ile bir SQL Fiddle var .

İstenen sonucu nasıl alabilirim?

Yanıtlar:


7

Bu PIVOT işlevi kullanılarak yapılabilir , ancak sorguyu schemaId'ye göre değiştirmek istediğiniz gibi göründüğü için dinamik SQL kullanmak isteyeceksiniz.

Bilinen sayıda değeriniz varsa veya belirli bir şema kimliği için sütunları biliyorsanız, sorguyu sabit olarak kodlayabilirsiniz. Statik bir sorgu şöyle olur:

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;

Demo ile SQL Fiddle bakın .

Bilinmeyen bir numaranız varsa veya SchemaIdbir yordama geçtiğinize göre sütunların değişmesini istiyorsanız, SQL dizesini oluşturmak için dinamik SQL kullanırsınız:

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

Demo ile SQL Fiddle bakın . Bu sorguların her ikisi de sonucu oluşturur:

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

3

Bu kalıbı kullanabilirsiniz. Daha fazla şema alanı için, tüm şema alanı adlarıyla 2.'den son satıra genişletin.

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;

Türün SchemaId = 1alanlarını temsil ediyorsa , aşağıdaki gibi bir şey kullanmanın Loantam listesini dinamik olarak da oluşturabilirsiniz 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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.