2017-08-09 43 views
4

我正在尋找一種方法來基於來自另一個SQL查詢的條件在表中轉換數據。動態「列」在選擇與轉換

我的表格如下;

DataTable: Id | EntityId |值1 |值2 |值3 ... Value200

實體: Id |名稱

Fields: Id | EntityId | DataType | FieldNum

查找: Id | EntityId | FieldId

我的理想的輸出如下所示:

  • Data.Id [ID]
  • Field.Id [FieldId]
  • Entity.Id [ENTITYID]
  • [StringVal]
  • [IntVal]

「StringVal」和「IntVal」都將基於「DataType」co設置如果設置爲「查找」(在「數據」表中存儲爲字符串),則應在此選擇查詢中將其解析爲整數,並填充到「IntVal」列中,否則,它應該直接解析到[StringVal]列。

我有下面的SQL查詢,它的工作原理是,但是,如果我有200個數據字段,我不得不復制每個字符串和查找的CASE和WHEN子句200次,然後有添加諸如「DateTime」之類的新類型的複雜性,這將導致進一步的問題。

SELECT 
    dt.Id as [Id], 
    f.Id as [FieldId], 
    f.EntityId as [EntityId], 
    CASE 
    WHEN f.DataType = 'string' and f.FieldNum = 0 THEN dt.Value0 
    WHEN f.DataType = 'string' and f.FieldNum = 1 THEN dt.Value1 
    WHEN f.DataType = 'string' and f.FieldNum = 2 THEN dt.Value2 
    WHEN f.DataType = 'string' and f.FieldNum = 3 THEN dt.Value3 
    WHEN f.DataType = 'string' and f.FieldNum = 4 THEN dt.Value4 
    WHEN f.DataType = 'string' and f.FieldNum = 5 THEN dt.Value5 
    WHEN f.DataType = 'string' and f.FieldNum = 6 THEN dt.Value6 
    WHEN f.DataType = 'string' and f.FieldNum = 7 THEN dt.Value7 
    WHEN f.DataType = 'string' and f.FieldNum = 8 THEN dt.Value8 
    WHEN f.DataType = 'string' and f.FieldNum = 9 THEN dt.Value9 
    ELSE NULL 
    END as [StringVal], 
    CAST(CASE 
    WHEN f.DataType = 'lookup' and f.FieldNum = 0 THEN dt.Value0 
    WHEN f.DataType = 'lookup' and f.FieldNum = 1 THEN dt.Value1 
    WHEN f.DataType = 'lookup' and f.FieldNum = 2 THEN dt.Value2 
    WHEN f.DataType = 'lookup' and f.FieldNum = 3 THEN dt.Value3 
    WHEN f.DataType = 'lookup' and f.FieldNum = 4 THEN dt.Value4 
    WHEN f.DataType = 'lookup' and f.FieldNum = 5 THEN dt.Value5 
    WHEN f.DataType = 'lookup' and f.FieldNum = 6 THEN dt.Value6 
    WHEN f.DataType = 'lookup' and f.FieldNum = 7 THEN dt.Value7 
    WHEN f.DataType = 'lookup' and f.FieldNum = 8 THEN dt.Value8 
    WHEN f.DataType = 'lookup' and f.FieldNum = 9 THEN dt.Value9 
    ELSE NULL 
    END as INT) as [IntVal] 
FROM Lookups as i 
    left JOIN Fields f on i.FieldId = f.id and i.EntityId = f.EntityId 
    INNER join DataTable dt on i.EntityId = dt.EntityId 

是否有更簡單的方法來實現這個目標?我需要保持這種索引視圖內,因此不能使用存儲過程,函數等

編輯:

試圖通過如在下面的評論指出函數來實現這一點,但是發現了同樣的問題。以下是我嘗試的功能解決方案。

SELECT 
    dt.Id as [Id], 
    f.Id as [FieldId], 
    f.EntityId as [EntityId], 
    CASE 
    WHEN f.DataType = 'string' THEN dbo.u_function_return_string 
     (
     f.FieldNum, dt.Value0, dt.Value1, 
     dt.Value2, dt.Value3, dt.Value4, 
     dt.Value5, dt.Value6, dt.Value7, 
     dt.Value8, dt.Value9 
    ) 
    ELSE NULL 
    END as [StringVal], 
    CAST(CASE 
    WHEN f.DataType = 'lookup' THEN dbo.u_function_returns_string 
     (
     f.FieldNum, dt.Value0, dt.Value1, 
     dt.Value2, dt.Value3, dt.Value4, 
     dt.Value5, dt.Value6, dt.Value7, 
     dt.Value8, dt.Value9 
    ) 
    ELSE NULL 
    END as INT) as [IntVal] 
FROM dbo.Lookups as i 
    INNER JOIN dbo.Fields f on i.FieldId = f.id and i.EntityId = f.EntityId 
    INNER join dbo.DataTable dt on i.EntityId = dt.EntityId 

功能:

CREATE FUNCTION u_function_return_string(
    @fieldNum INT, 
    @val0 NVARCHAR(255), 
    @val1 NVARCHAR(255), 
    @val2 NVARCHAR(255), 
    @val3 NVARCHAR(255), 
    @val4 NVARCHAR(255), 
    @val5 NVARCHAR(255), 
    @val6 NVARCHAR(255), 
    @val7 NVARCHAR(255), 
    @val8 NVARCHAR(255), 
    @val9 NVARCHAR(255) 
) 
RETURNS NVARCHAR(255) WITH SCHEMABINDING 
AS BEGIN 
RETURN 
    CASE 
    WHEN @fieldNum = 0 THEN @val0 
    WHEN @fieldNum = 1 THEN @val1 
    WHEN @fieldNum = 2 THEN @val2 
    WHEN @fieldNum = 3 THEN @val3 
    WHEN @fieldNum = 4 THEN @val4 
    WHEN @fieldNum = 5 THEN @val5 
    WHEN @fieldNum = 6 THEN @val6 
    WHEN @fieldNum = 7 THEN @val7 
    WHEN @fieldNum = 8 THEN @val8 
    WHEN @fieldNum = 9 THEN @val9 
    END 
END 
GO 

有什麼辦法嵌入一個 「行」 到一個函數?理想情況下,我想提交2個參數,即字段號和「dt」結果集。

編輯2:

找到一種方法,使一個功能拍攝一類...這作品...但不能從查詢找出如何解析成「DT *。」鍵入並傳遞給函數。

CREATE OR ALTER FUNCTION u_function_return_string(
    @fieldNum INT, 
    @data dbo.DataTableType READONLY 
) 
RETURNS NVARCHAR(255) WITH SCHEMABINDING 
AS BEGIN 
    DECLARE @tmp NVARCHAR(255) 
    DECLARE @value NVARCHAR(255) 
    set @tmp = 'Value' + CAST(@fieldNum as NVARCHAR(50)) 
    SET @value = (SELECT @tmp FROM @data) 
    RETURN @value 
END 
GO 
+0

歡迎來到EAV的世界。 – lad2025

+3

對於玩玩方式:[實體屬性值] http://sqlblog.com/blogs/aaron_bertrand/archive/2009/11/19/what-is-so-bad-about-eav-anyway.aspx – xQbert

+0

看起來像一個類似的方法來實現最終目標,但是並不能幫助我解決我的問題:( –

回答

0

您可以使用標量值模式綁定函數和動態sql,並使用select查詢中的一個case函數調用替換多個case語句。

我已修改您的查詢以解釋該方法。請根據您的要求進行更改。

SELECT 
    dt.Id as [Id], 
    f.Id as [FieldId], 
    f.EntityId as [EntityId], 
    CASE 
    WHEN f.DataType = 'string' THEN 
     dbo.fn_getvalue(f.FieldNum,f.EntityId) 
    ELSE NULL 
    END as [StringVal], 
    CAST(CASE 
    WHEN f.DataType = 'lookup' THEN 
     dbo.fn_getvalue(f.FieldNum,f.EntityId) 
    ELSE NULL 
    END as INT) as [IntVal] 
FROM Lookups as i 
    left JOIN Fields f on i.FieldId = f.id and i.EntityId = f.EntityId 
    INNER join DataTable dt on i.EntityId = dt.EntityId 




    CREATE FUNCTION [dbo].[fn_getvalue] 
    (@param1 int, @param2 int) 
    RETURNS nvarchar(255) WITH SCHEMABINDING 
    AS 
    BEGIN 
     declare @sql nvarchar(max); 
     declare @output nvarchar(50); 

     set @sql = 'SELECT @field=Value' + @param1 + ' FROM DataTable WHERE EntityId = ' + cast(@param2 as nvarchar); 

     execute sp_executesql @sql,N'@field nvarchar(50) OUTPUT', @field = @output OUTPUT; 
     return @output; 
    END 
+0

不幸的是,使用這種方法,性能會急劇下降在大約10K條記錄之後 - 與案例陳述相比,它在執行查詢方面相對一致。 –