2012-02-08 48 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

相关问题