Таблицы SQL: можно ли сводить / объединять с N строками? - PullRequest
2 голосов
/ 08 февраля 2012

Во-первых, я новичок в SQL, во-вторых, если есть лучшее решение, которое может быть реализовано в коде позже, я бы хотел это услышать. Кроме того, данные в настоящее время хранятся в MySQL, но в конечном итоге их придется портировать на MSSQL, чтобы было лучше использовать решение для нескольких баз данных (если оно существует).

Теперь проблема, мои упрощенные данные выглядят так:

[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 DataGrids, чтобы была возможность привязки напрямую к представлению с правильными данными. .

Ответы [ 2 ]

2 голосов
/ 08 февраля 2012

Да, но только при использовании динамического 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 
        ,'' --@ProzedurDetail
    ;


    --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, с MIME, определенным в RTR_nCode, на случай, если вам интересно.

0 голосов
/ 08 февраля 2012

Нет - невозможно написать запрос с динамическим числом столбцов.

Ваш выбор (в порядке предпочтения):

  1. написать запрос, который имеет «много» столбцов, некоторые из которых могут быть пустыми (их легко написать и использовать, но при этом будет максимальный размер ширины сводной области)
  2. написать код приложения, который напишет для вас динамический запрос (не так уж плохо: portable)
  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.

Кроме того, вам необходимо знать идентификаторы стилей, и они должны быть одинаковыми во всех средах. Если это не так (например, отличается в тестовой / рабочей среде), вы можете изменить a1.style = 1 на a1.style = (select id from style where name = 'A Style') и т. Д. - он все равно будет работать нормально.

...