2012-02-08 70 views
2

首先,我是一個SQL noob,其次如果有更好的解決方案可以在代碼中實現後,我很樂意聽到它。此外,數據目前存儲在MySQL中,但最終必須移植到MSSQL,因此跨DB解決方案將是最好的(如果存在的話)。SQL表:我可以透視/連接N行嗎?

現在,這個問題,我簡單的數據是這樣的:

[STYLES] 
ID NAME 
1 A Style 
2 B Style 
... 
N N Style 

[EQUIPMENT] 
ID NAME 
1 A Equipment 
2 B Equipment 
... 
N N Equipment 

[AVAILABILITY] 
STYLE EQUIPMENT TYPE 
1  1   Standard 
1  2   Optional 
2  1   Optional 
... #items will be missing and represent not available 
2  2   Standard 

現在我需要一臺看起來像這樣:

[DESIRED_VIEW] 
EQUIPMENT_NAME A_STYLE_TYPE B_STYLE_TYPE ... N_STYLE_TYPE 
A Equipment  Standard  Optional  ... NULL 
B Equipment  Optional  NULL   ... Standard 

我已經看到了一些簡單的數據透視例子,他們都依賴於具有一定數量的列。有沒有一種方法可以根據STYLES表中的行數設置可變數量的列的視圖?

作爲一個說明,我使用Visual Studio創建Data xsd並讓它自動生成表格填充方法,然後在WPF DataGrid中顯示信息,以便能夠直接綁定到具有正確數據的視圖理想。

回答

0

否 - 無法編寫具有動態列數的查詢。

您的選擇是(按優先順序排列):

  1. 寫有列,其中一些可能是空白的(容易編寫和使用的「大量」的查詢,但是會有一個硬盤上的最大值)
  2. 編寫應用程序代碼,爲您寫入動態查詢(不是太糟糕:便攜式)
  3. 編寫一個存儲過程來創建SQL(糟糕的選擇:痛苦地在PL/SQL並且完全不可移植)

如果您熟悉的風格的最大數目(它可以任意大,但有限的),代碼的支點應該是這樣的:

select 
    e.name as equipment_name, 
    a1.type as a_style_type, 
    a2.type as b_style_type, 
    a3.type as c_style_type, 
    ... 
    an.type as n_style_type 
from equipment e 
left join availability a1 on a1.equipment = e.id and a1.style = 1 
left join availability a2 on a2.equipment = e.id and a2.style = 2 
left join availability a3 on a3.equipment = e.id and a3.style = 3 
... 
left join availability an on an.equipment = e.id and an.style = 999; 

當有一個給定的風格沒有可用的類型,你會得到一個NULL

此外,您需要知道樣式id​​,並且它們在所有environemtns上都必須相同。如果情況並非如此(例如,在測試/刺激環境中不同),則可以將a1.style = 1更改爲a1.style = (select id from style where name = 'A Style')等 - 它仍然可以正常工作。

+0

MS-SQL使用T-SQL,而不是PL/SQL。除此之外,一個不可移植的存儲過程可以針對目標系統進行重寫 - 但無疑經常需要考慮。而複雜的查詢幾乎不可移植。 – 2012-02-08 14:51:29

+0

我跟着上面的數字2使用代碼來建立選擇使用您提供的相同的語法,謝謝。 – bejumi 2012-02-09 09:22:33

+0

@bejumi:這是個好主意。 – 2012-02-09 12:12:42

2

是的,但僅當使用動態SQL(存儲過程)時。 在這裏,在現實生活中使用

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_RPT_Report_Translation]') AND type in (N'P', N'PC')) 
DROP PROCEDURE [dbo].[sp_RPT_Report_Translation] 
GO 







-- =========================================================== 
-- Author:  [CENSORED] 
-- Create date: 14.04.2011 
-- Last modified: 17.01.2012 
-- Description: Übersetzung für Berichte 
-- =========================================================== 
-- Pre: Valid Report Name & datetime 
-- Post: Translation for language in first row with rownames as defined 
--  for each item in T_RPT_Translations.RTR_ItemCaption 
CREATE PROCEDURE [dbo].[sp_RPT_Report_Translation] 
    @in_mandant varchar(3) 
    ,@in_sprache varchar(2) 
    ,@in_stichtag varchar(50) 
    ,@in_report_name nvarchar(1000) 
AS 
BEGIN 
    DECLARE 
    @strSQL NVARCHAR(MAX) 
    ,@strReportName NVARCHAR(1000) 
    ,@strPivotColumns NVARCHAR(MAX) 
    ,@stichtag DATETIME 


    -- Abrunden des Eingabedatums auf 00:00:00 Uhr 
    SET @stichtag = CONVERT(DATETIME, @in_stichtag) 
    SET @stichtag = CAST(FLOOR(CAST(@stichtag AS Float)) AS DateTime) 
    SET @in_stichtag = CONVERT(varchar(50), @stichtag) 

    SET NOCOUNT ON; 

    SET @strReportName = REPLACE(@in_report_name, N'''', '''''') 

    -- http://geekswithblogs.net/baskibv/archive/2008/07/03/123567.aspx 
    SELECT 
     @strPivotColumns = COALESCE(@strPivotColumns, '') + '[' + [RTR_ItemCaption] + '], ' 
    FROM T_RPT_Translations 
    WHERE (RTR_Status = 1) 
     AND (RTR_MDT_ID = @in_mandant) 
     AND 
     ( 
      (RTR_ReportName = @strReportName) 
      OR 
      (RTR_ReportName = 'PARA_ALL') 
     ) 
     --AND (RTR_ItemCaption != 'RPT_Title') 
     AND (RTR_ItemCaption IS NOT NULL) 
     AND 
     (
       (RTR_IsFlag != 1) 
       OR 
       (RTR_IsFlag IS NULL) 
     ) 
     AND (RTR_ItemCaption != '') 
    ORDER BY RTR_Sort 



    SET @strPivotColumns = SUBSTRING(@strPivotColumns, 0, LEN(@strPivotColumns)) 
    SET @strPivotColumns = REPLACE(@strPivotColumns, N'''', '''''') 

    --PRINT @strPivotColumns 

    SET @strSQL = ' 
     SELECT TOP(1) * FROM 
     ( 
      SELECT 
       RTR_ItemCaption 
       --,RTR_Kurz_' + @in_sprache + ' 
       ,RTR_Lang_' + @in_sprache + ' 
      FROM T_RPT_Translations 
      WHERE (RTR_MDT_ID = ''' + @in_mandant+ ''') 
       AND 
       ( 
        (RTR_ReportName = ''' + @strReportName + ''') 
        OR 
        (RTR_ReportName = ''PARA_ALL'') 
       ) 
       --AND (RTR_ItemCaption != ''RPT_Title'') 
       AND (RTR_Status = 1) 
       AND (RTR_ItemCaption IS NOT NULL) 
       AND 
       (
        (RTR_IsFlag != 1) 
        OR 
        (RTR_IsFlag IS NULL) 
       ) 
       AND (RTR_ItemCaption != '''') 

     ) AS SourceTable 
     PIVOT 
     ( 
      MAX(RTR_Lang_' + @in_sprache + ') 
      FOR RTR_ItemCaption IN 
      (' 
       + @strPivotColumns + 
      ') 

     ) AS PivotTable 

     --ORDER BY RPT_RM_SO_Bezeichnung, RPT_RM_GB_Bezeichnung, RPT_RM_NutzungGruppeCode 
    ' 

    DECLARE @ProzedurParameter nvarchar(max) 
    SET @ProzedurParameter = ' 
    DECLARE @in_mandant varchar(3) 
    ,@in_sprache varchar(2) 
    ,@in_stichtag varchar(50) 
    ,@in_report_name nvarchar(1000) 
    ; 

    SET @in_mandant = ''' + REPLACE(@in_mandant, '''', '''''') + '''; 
    SET @in_sprache = ''' + REPLACE(@in_sprache, '''', '''''') + '''; 
    SET @in_stichtag = ''' + REPLACE(@in_stichtag, '''', '''''') + '''; 
    SET @in_report_name = ''' + REPLACE(@in_report_name, '''', '''''') + '''; 
    ' 



    EXECUTE sp_RPT_DEBUG_LOG_ProzedurRun 
     'sp_RPT_Report_Translation' 
     ,@ProzedurParameter 
     ,@strSQL 
     ,'' [email protected] 
    ; 


    --PRINT @strSQL 
    EXECUTE (@strSQL) 

END 



GO 

此表的例子:

CREATE TABLE [dbo].[T_RPT_Translations](
    [RTR_UID] [uniqueidentifier] NULL, 
    [RTR_ReportName] [nvarchar](1000) NULL, 
    [RTR_MDT_ID] [int] NULL, 
    [RTR_ItemCaption] [nvarchar](50) NULL, 
    [RTR_Code] [int] NULL, 
    [RTR_nCode] [nvarchar](100) NULL, 
    [RTR_Kurz_DE] [nvarchar](20) NULL, 
    [RTR_Kurz_FR] [nvarchar](20) NULL, 
    [RTR_Kurz_IT] [nvarchar](20) NULL, 
    [RTR_Kurz_EN] [nvarchar](20) NULL, 
    [RTR_Lang_DE] [nvarchar](100) NULL, 
    [RTR_Lang_FR] [nvarchar](100) NULL, 
    [RTR_Lang_IT] [nvarchar](100) NULL, 
    [RTR_Lang_EN] [nvarchar](100) NULL, 
    [RTR_Img_DE] [varchar](max) NULL, 
    [RTR_Img_FR] [varchar](max) NULL, 
    [RTR_Img_IT] [varchar](max) NULL, 
    [RTR_Img_EN] [varchar](max) NULL, 
    [RTR_Img_Width] [int] NULL, 
    [RTR_Img_Height] [int] NULL, 
    [RTR_Img_PaddingLeft] [float] NULL, 
    [RTR_Img_PaddingRight] [float] NULL, 
    [RTR_Img_PaddingTop] [float] NULL, 
    [RTR_Img_PaddingBottom] [float] NULL, 
    [RTR_Img_Hide] [bit] NULL, 
    [RTR_IsLogo] [bit] NULL, 
    [RTR_IsFlag] [bit] NULL, 
    [RTR_Sort] [int] NULL, 
    [RTR_Status] [int] NULL, 
    [RTR_DatumVon] [datetime] NULL, 
    [RTR_DatumBis] [datetime] NULL 
) ON [PRIMARY] 

GO 

SET ANSI_PADDING OFF 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_UID] DEFAULT (newid()) FOR [RTR_UID] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_ReportName] DEFAULT (N'InsertError') FOR [RTR_ReportName] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_MDT_ID] DEFAULT ((0)) FOR [RTR_MDT_ID] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_ItemCaption] DEFAULT (N'InsertError') FOR [RTR_ItemCaption] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_IsLogo] DEFAULT ((0)) FOR [RTR_IsLogo] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_IsFlag] DEFAULT ((0)) FOR [RTR_IsFlag] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_Sort] DEFAULT ((0)) FOR [RTR_Sort] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_Status] DEFAULT ((1)) FOR [RTR_Status] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_DatumVon] DEFAULT ('17530101') FOR [RTR_DatumVon] 
GO 

ALTER TABLE [dbo].[T_RPT_Translations] ADD CONSTRAINT [DF_T_RPT_Translations_RTR_DatumBis] DEFAULT ('99991231') FOR [RTR_DatumBis] 
GO 

如果你不理解的參數,這是在德國:

@in_sprache: in_language 
@in_stichtag: in_ReportingDate 
DatumVon: DateFrom 
DatumBis: DateTo 
rest is clear 

RTR_Img_XX是一個base64編碼的圖像,在RTR_nCode中定義了mime,以防萬一。

+0

感謝您的快速響應,正如我所說的,我仍然對SQL有所瞭解,而且您的答案有很多我需要花費的精力(包括德語評論?),所以我需要一些時間來嘗試將其應用於我自己的案例。 – bejumi 2012-02-08 12:53:15

+0

查看存儲過程的註釋行中的geekswithblogs鏈接,它解釋了聚合使用。唯一的德語評論是「 - Abrunden des Eingabedatums auf 00:00:00 Uhr」,意思是將輸入日期(in_stichtag)舍入到0點,所以你不會得到一個日期時間(如in DateTime.Now),並將其與沒有時間的日期時間進行比較(同一天,但是0點 - 你知道31.12.2011 00:00 <31.12.2011 15:00)。對於其他內容:http://www.google.com/translate – 2012-02-08 14:47:51

相關問題