4

DBMS に Sql Server 2012 を使用しています。

私のデータベースには、一連のカタログ テーブルに関連する Product テーブルがあります。これらのカタログ テーブルは、さまざまな製品カテゴリを表します。すべての製品には共通の特定の属性 (当社の内部識別子、サプライヤー、コストなど) がありますが、製品の詳細はさまざまです (家具はデジタル製品と同じようには記述されません)。 .

さらに、各製品には親エンティティがあります。親は複数の子 (この場合は製品) を持つ場合があります。

私の仕事は、指定された親 ID のリストの製品と関連情報を選択し、その情報を XML ドキュメントに入力することです。

私が現在作業しているテーブルは次のとおりです。

  • 製品
  • PRODUCT_DIGITAL
  • PRODUCT_FURNITURE

製品には、Product_Id で PRODUCT_DIGITAL との PK/FK 関係があります。PRODUCT から PRODUCT_FURNITURE にも同じタイプの関係が存在します。

製品が次のようになっている場合:

PRODUCT_ID -- PRODUCT_CATEGORY -- PARENT_ID -- PARENT_TYPE -- DELIVERY_IN_DAYS
100           DIG                 1            1              7
101           DIG                 1            1              8
102           DIG                 1            1              1
103           DIG                 2            1              2
104           DIG                 2            1              1

PRODUCT_DIGITAL は次のようになります。

PRODUCT_ID -- PRODUCT_TYPE -- PRODUCT_NAME -- PRODUCT_MNEMONIC
100           A               IMG1            IMAWTRFL
101           B               SND1            SNDENGRV
102           B               SND2            SNDHRSLF
103           A               IMG2            IMGNBRTO
104           B               SND3            SNDGTWNE

最後に、次のような結果セットが必要です。

PRODUCT_CATEGORY -- PRODUCT_ID -- PRODUCT_TYPE -- PARENT_ID -- DELIVERY_IN_DAYS -- PROD_EXTENSION_NAME -- PROD_EXTENSION_TYPE -- PROD_EXTENSION_VALUE
DIG                 100           A               1            7                   PRODUCT_NAME           STRING                 IMG1
DIG                 100           A               1            7                   PRODUCT_MNEMONIC       STRING                 IMAWTRFL
DIG                 101           B               1            8                   PRODUCT_NAME           STRING                 SND1
DIG                 101           B               1            8                   PRODUCT_MNEMONIC       STRING                 SNDENGRV
DIG                 102           B               1            1                   PRODUCT_NAME           STRING                 SND2
DIG                 102           B               1            1                   PRODUCT_MNEMONIC       STRING                 SNDHRSLF
DIG                 103           A               2            2                   PRODUCT_NAME           STRING                 IMG2
DIG                 103           A               2            2                   PRODUCT_MNEMONIC       STRING                 IMGNBRTO
DIG                 104           B               2            1                   PRODUCT_NAME           STRING                 SND3
DIG                 104           B               2            1                   PRODUCT_MNEMONIC       STRING                 SNDGTWNE

最初の検索で UNPIVOT にたどり着きましたが、これまでのところ、理解できていません。私が最終的に行ったことは、一時テーブルを作成してパスで更新し、最終的な選択のために製品テーブルに結合することでした:

create table #tbl(product_id int, prod_extension_name varchar(100), prod_extension_type varchar(100), prod_extension_value varchar(1000))

insert into #tbl
select p.product_id, c.column_name, 
case c.data_type
when 'varchar' then 'string'
else data_type end as data_type
, null
from dbo.product p, information_schema.columns c
where c.table_name = 'PRODUCT_DIGITAL'
and c.column_name in ('PRODUCT_NAME','PRODUCT_MNEMONIC')

update #tbl
set prod_extension_value = p.product_name
from dbo.product p
where #tbl.product_id = p.product_id
and #tbl.colname = 'PRODUCT_NAME'

update #tbl
set prod_extension_value = p.product_mnemonic
from dbo.product p
where #tbl.product_id = p.product_id
and #tbl.colname = 'PRODUCT_MNEMONIC'

select p.product_category, p.product_id, pd.product_category, #tbl.prod_extension_name, #tbl.prod_extension_type, #tbl.prod_extension_value
from dbo.product p inner join dbo.product_digital pd on p.product_id = pd.product_id
inner join #tbl on p.product_id = #tbl.product_id
order by product_id

誰かがこれを行うためのより良い方法を教えてもらえますか? 複数の更新などを行うことなく、これをより速く行うことができるように思われます.

4

2 に答える 2

4

これはあなたが望むことをすると思います。これは関数を実装し、ビューUNPIVOTから列情報を取得して結果を取得します。information_schema.columns

select product_id,
  product_category,
  parent_id,
  delivery_in_days,
  PROD_EXTENSION_NAME,
  case when c.data_type = 'varchar' 
      then 'STRING' else null end as PROD_EXTENSION_TYPE,
  PROD_EXTENSION_VALUE
from
(
  select 
    p.product_id,
    p.product_category,
    p.parent_id,
    p.delivery_in_days,
    PRODUCT_NAME,
    PRODUCT_MNEMONIC
  from product p
  left join product_digital pd
    on p.product_id = pd.product_id
) src
unpivot
(
  PROD_EXTENSION_VALUE
  for PROD_EXTENSION_NAME in (PRODUCT_NAME, PRODUCT_MNEMONIC)
) up
inner join 
(
  select c.column_name, c.data_type
    from information_schema.columns c
    where c.table_name = 'PRODUCT_DIGITAL'
      and c.column_name in ('PRODUCT_NAME','PRODUCT_MNEMONIC')
) c
  on up.PROD_EXTENSION_NAME = c.column_name           

デモで SQL Fiddle を参照してください

結果は次のとおりです。

| PRODUCT_ID | PRODUCT_CATEGORY | PARENT_ID | DELIVERY_IN_DAYS | PROD_EXTENSION_NAME | PROD_EXTENSION_TYPE | PROD_EXTENSION_VALUE |
-----------------------------------------------------------------------------------------------------------------------------------
|        100 |              DIG |         1 |                7 |        PRODUCT_NAME |              STRING |                 IMG1 |
|        100 |              DIG |         1 |                7 |    PRODUCT_MNEMONIC |              STRING |             IMAWTRFL |
|        101 |              DIG |         1 |                8 |        PRODUCT_NAME |              STRING |                 SND1 |
|        101 |              DIG |         1 |                8 |    PRODUCT_MNEMONIC |              STRING |             SNDENGRV |
|        102 |              DIG |         1 |                1 |        PRODUCT_NAME |              STRING |                 SND2 |
|        102 |              DIG |         1 |                1 |    PRODUCT_MNEMONIC |              STRING |             SNDHRSLF |
|        103 |              DIG |         2 |                2 |        PRODUCT_NAME |              STRING |                 IMG2 |
|        103 |              DIG |         2 |                2 |    PRODUCT_MNEMONIC |              STRING |             IMGNBRTO |
|        104 |              DIG |         2 |                1 |        PRODUCT_NAME |              STRING |                 SND3 |
|        104 |              DIG |         2 |                1 |    PRODUCT_MNEMONIC |              STRING |             SNDGTWNE |

編集 #1: このタイプの変換を動的に実行する場合は、動的 SQL を使用する必要があります。これを行うには、以下を使用します。

まず、次の列のリストを取得する必要がありますUNPIVOT

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('PRODUCT_DIGITAL') and
               C.name not in ('PRODUCT_ID', 'PRODUCT_TYPE') -- include the items you DO NOT want to unpivot
         for xml path('')), 1, 1, '')

最終的なスクリプトは次のようになります。

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('PRODUCT_DIGITAL') and
               C.name not in ('PRODUCT_ID', 'PRODUCT_TYPE')
         for xml path('')), 1, 1, '')

select @cols = stuff((select ', '''+C.name + ''''
         from sys.columns as C
         where C.object_id = object_id('PRODUCT_DIGITAL') and
               C.name not in ('PRODUCT_ID', 'PRODUCT_TYPE')
         for xml path('')), 1, 1, '')

set @query 
  = '  select
          product_id,
          product_category,
          parent_id,
          delivery_in_days,
          PROD_EXTENSION_NAME,
          case when c.data_type = ''varchar'' 
              then ''STRING'' else null end as PROD_EXTENSION_TYPE,
          PROD_EXTENSION_VALUE
        from 
        (
          select 
            p.product_id,
            p.product_category,
            p.parent_id,
            p.delivery_in_days,
            PRODUCT_NAME,
            PRODUCT_MNEMONIC
          from product p
          left join product_digital pd
            on p.product_id = pd.product_id
        ) src
        unpivot
        (
          PROD_EXTENSION_VALUE
          for PROD_EXTENSION_NAME in ('+ @colsunpivot +')
        ) up
        inner join 
        (
          select c.column_name, c.data_type
          from information_schema.columns c
          where c.table_name = ''PRODUCT_DIGITAL''
            and c.column_name in ('+@cols+')
        ) c
          on up.PROD_EXTENSION_NAME = c.column_name'


exec(@query)

SQL Fiddle with Demoを参照してください。これは、動的であることを除いて、元のバージョンと同じ結果を生成します。

于 2013-01-09T23:58:28.723 に答える
0

私は飛び跳ねているかもしれませんが、最終的な出力はXMLである必要があるとあなたは言います。私はあなたのすべての要件を含めていませんが、このようなものはあなたの要件に合っていますか?(私はあなたの要件を単純化しすぎたかもしれないと思います)

;WITH PRODUCT (PRODUCT_ID, PRODUCT_CATEGORY, PARENT_ID, PARENT_TYPE, DELIVERY_IN_DAYS) AS
(
    SELECT 100, 'DIG', 1, 1, 7  UNION ALL
    SELECT 101, 'DIG', 1, 1, 8  UNION ALL
    SELECT 102, 'DIG', 1, 1, 1  UNION ALL
    SELECT 103, 'DIG', 2, 1, 2  UNION ALL
    SELECT 104, 'DIG', 2, 1, 1
)
,PRODUCT_DIGITAL (PRODUCT_ID, PRODUCT_TYPE, PRODUCT_NAME, PRODUCT_MNEMONIC) AS
(
    SELECT 100, 'A', 'IMG1', 'IMAWTRFL' UNION ALL
    SELECT 101, 'B', 'SND1', 'SNDENGRV' UNION ALL
    SELECT 102, 'B', 'SND2', 'SNDHRSLF' UNION ALL
    SELECT 103, 'A', 'IMG2', 'IMGNBRTO' UNION ALL
    SELECT 104, 'B', 'SND3', 'SNDGTWNE'
)

SELECT   P.PRODUCT_CATEGORY
        ,P.PRODUCT_ID
        ,P.PARENT_TYPE
        ,P.PARENT_ID
        ,P.DELIVERY_IN_DAYS
        ,PD.PRODUCT_NAME
        ,PD.PRODUCT_MNEMONIC
FROM PRODUCT            P
JOIN PRODUCT_DIGITAL    PD  ON P.PRODUCT_ID = PD.PRODUCT_ID
FOR XML PATH
于 2013-01-10T12:00:14.397 に答える