Определения динамических полей - это можно сделать в T-SQL? - PullRequest
2 голосов
/ 28 апреля 2011

У меня есть требование, которое я пытаюсь выполнить.Если возможно, я бы хотел добиться этого с помощью собственного T-SQL.

У меня есть следующие таблицы:

CUSTOMER
========
ID,
Name

FIELDDEF
========
ID,
Name
FieldType   (Char  T, N, D   for Text, Number or Date)

CUSTOMERFIELD
=============
ID,
CustomerID,
FieldDefID,
CaptureDate,
ValueText,
ValueNumber,
ValueDate

По сути, целью этих таблиц является предоставление расширяемого пользовательскогополевая система.Идея состоит в том, что пользователь создает новые определения полей, которые могут быть текстовым, числовым или датным полем.Затем они создают значения для этих полей в поле ValueText, ValueNumber ИЛИ ValueDate.

Пример:

*Customer*
1,BOB
2,JIM

*FieldDef*
1,Mobile,T
1,DateOfBirth,D

*CustomerField*
ID,CustomerID,FieldDefID,CaptureDate,ValueText,ValueNumber,ValueDate
1,1,1,2011-01-1,07123456789,NULL,NULL
2,1,2,2011-01-1,NULL,NULL,09-DEC-1980
3,1,1,2011-01-2,07123498787,NULL,NULL

Мне нужно создать представление, которое выглядит следующим образом:

*CustomerView*
ID,Name,Mobile,DateOfBirth
1,BOB,07123498787,09-DEC-1980

Обратите внимание, что мобильный телефон Боба является вторым в списке, поскольку он использует самую последнюю дату захвата.

В идеале мне нужно, чтобы это было расширяемым, поэтому, если я создаюновое поле def в будущем, оно автоматически выбирается в CustomerView.

Возможно ли это вообще в T-SQL?

Спасибо,

Саймон.

Ответы [ 3 ]

1 голос
/ 28 апреля 2011

Это не было бы возможно для представления, если только представление не динамически воссоздается на лету каждый раз, когда FieldDef изменяется, потому что схемы представления заблокированы во время создания.Однако это может быть возможно с хранимой процедурой, которая может работать или не работать в зависимости от того, как вы ее используете.

Редактировать 1

Вот пример запросаэто работает только для ваших текущих имен полей и должно было бы быть изменено динамическим SQL для общей работы:

Редактировать 2

Изменено, чтобы получать новейшие значения изтаблица полей клиента

with CustomerFieldNewest as (
    select
        cf1.*
    from
        customerfield cf1
    inner join
        (
            select
                customerid,
                fielddefid,
                max(capturedate) as maxcapturedate
            from
                customerfield cf2
            group by
                customerid,
                fielddefid
        ) cf2 on cf1.customerid = cf2.customerid
            and cf1.fielddefid = cf2.fielddefid
            and cf1.capturedate = cf2.maxcapturedate
)
,CustomerFieldPivot as (
    select
        C.ID as ID
        ,max(case when F.Name = 'Mobile' then CF.ValueText end) as Mobile
        ,max(case when F.Name = 'DateOfBirth' then CF.ValueDate end) as DateOfBirth
    from
        Customer C
    left join
        CustomerFieldNewest CF on C.ID = CF.CustomerID
    left join
        FieldDef F on F.ID = CF.FieldDefID
    group by
        C.ID
)
select
    C.*
    ,P.Mobile
    ,P.DateOfBirth
from
    Customer C
left join
    CustomerFieldPivot P on C.ID = P.ID

Редактировать 3

Вот код T-SQL для генерации представления на лету на основе текущего набора полей в FieldDef (это предполагает, что представление CustomerView уже существует, поэтому вам нужно сначала создать его как пустое определение, иначе вы получите ошибку).Я не уверен насчет производительности всего этого, но он должен работать правильно.

declare @sql varchar(max)
declare @fielddef varchar(max)
declare @fieldlist varchar(max)

select
    @fielddef = coalesce(@fielddef + ', ' + CHAR(13) + CHAR(10), '') +
        '           max(case when F.Name = ''' + F.Name + ''' then CF.' +
            case F.FieldType
                when 'T' then 'ValueText'
                when 'N' then 'ValueNumber'
                when 'D' then 'ValueDate'
            end
        + ' end) as [' + F.Name + ']'

    ,@fieldlist = coalesce(@fieldlist + ', ' + CHAR(13) + CHAR(10), '') +
        '       [' + F.Name + ']'
from
    FieldDef F

set @sql = '
    alter view [CustomerView] as

    with CustomerFieldNewest as (
        select
            cf1.*
        from
            customerfield cf1
        inner join
            (
                select
                    customerid,
                    fielddefid,
                    max(capturedate) as maxcapturedate
                from
                    customerfield cf2
                group by
                    customerid,
                    fielddefid
            ) cf2 on cf1.customerid = cf2.customerid
                and cf1.fielddefid = cf2.fielddefid
                and cf1.capturedate = cf2.maxcapturedate
    )
    ,CustomerFieldPivot as (
        select
            C.ID as ID,
' + @fielddef + '
        from
            Customer C
        left join
            CustomerFieldNewest CF on C.ID = CF.CustomerID
        left join
            FieldDef F on F.ID = CF.FieldDefID
        group by
            C.ID
    )
    select
        C.*,
' + @fieldlist + '
    from
        Customer C
    left join
        CustomerFieldPivot P on C.ID = P.ID
'

print @sql
exec(@sql)

select * from CustomerView
1 голос
/ 28 апреля 2011

Просто для полноты есть sql_variant:

 declare @t table (typ varchar(1), yuk sql_variant)
   insert @t values ('d', getdate())
   insert @t values ('i', 1234)
   insert @t values ('s', 'bleep bloop')

 select
    yuk, 
    case typ 
        when 'd' then convert(datetime, yuk, 106)+50
        when 'i' then cast(yuk as int) * 2
        when 's' then reverse(cast(yuk as varchar))
        else yuk
    end
 from @t
1 голос
/ 28 апреля 2011

Вам необходимо создать кросс-таблицу, которую вы делаете с помощью оператора Pivot в TSQL. Вот статья, в которой рассказывается о том, как динамически построить пивот.

http://sqlserver -qa.net / блоги / T-SQL / Архив / 2008/08/27 / 4809.aspx

...