2017-10-11 27 views
2

我的問題有點不尋常。SQL:從另一個表動態構建表格

我有3列(SQL Fiddle Link)的表:

ItemIdentifer ItemClasses   RelevantItemDetails 

Item1   Software    <xml document> 
Item1   CRM     <xml document> 

現在,我需要做的是:

  1. 與給定的標識符選擇行。 (比如Item1)

  2. 爲每個具有給定標識符的行生成一個臨時表:例如Table_Name是該行的ItemClass。 (因此,在這種情況下,我將擁有2個表格 - 軟件和CRM。)

  3. 將RelevantItemDetails value => xml text =>轉換爲相應表格的表項(我知道這個:)) 。

我學會了通過openxml頁面https://docs.microsoft.com/en-us/sql/t-sql/functions/openxml-transact-sql來完成第3步。我創建了一個從XML返回表的SQL過程。現在,我只需將其插入到我在步驟2中創建的臨時表中(包含列名和值)。而且我迷失了這一點。

我懷疑對於1 & 2,我必須建立一個動態地完成這些事情的過程。

任何幫助將是非常有益的。

澄清:我沒有得到兩件事情:

  1. 動態地構建一個表與itemClass時的名稱作爲表名。 (所以,Item1的2個表格在這裏)。

  2. 該表的行和列由xml文檔(即另一個表)定義。

所以,我只需要創建由XML文檔定義與itemClass時定義的名稱表和 列和行條目(假設我從XML創建 表,它也將是動態生成,但我知道如何生成它)。

我在這裏讀取動態創建表(T-SQL How to create tables dynamically in stored procedures?),但這些列是固定的。在我的情況下,列是從另一個表派生的。而且我也必須插入值(再一次,從列來的同一張表派生)。

編輯:樣品行。

ID ItemName ItemClass Details 
10 WebApp  Software <root><row ID="10" ItemName="WebApp" ItemDescription="desc" DisplayID="4962" /></root> 

編輯:樣品決賽桌。

TableName == Software 

ID ItemName ItemDescription DisplayID 
10 WebApp "desc"   4962 
+0

你的sql小提琴沒有任何xml。它只有字符串「xml」。我們無法幫助您從中創建代碼來創建表格。它是建立在MySQL,而不是SQL服務器。 –

+0

@SeanLange感謝您檢查我的問題。是的,我說我們可以假設我從xml中提取了一個表。所以,而不是xml:考慮任何表格:plz看到這個:http://www.sqlfiddle.com/#!9/6de0da/1/0:我必須從xml table =>獲取列名稱和行和表班級名稱。我找不到任何地方演示sql server。有沒有sql server小提琴的東西? –

+0

所以你只需要幫助來創建表格?在你的問題中,你說你需要那個部分。這是問題。您聲明您知道如何獲取列,但不能創建腳本來創建表。我們無法幫助您,因爲表格和列需要使用相同的語句。 –

回答

1

@items表類似於您當前的表。然後有步驟爲每個ItemClass生成腳本。

DECLARE @n int, -- counter 
     @i int = 0, -- counter 
     @tableName nvarchar(255), -- stores name of the current table 
     @query nvarchar(4000) -- stores a query that creates table 

-- creates table like yours 
DECLARE @items TABLE (
    ID int, 
    ItemName nvarchar(100), 
    ItemClass nvarchar(100), 
    Details xml 
) 
-- put some data in a table 
INSERT INTO @items VALUES 
(10, N'WebApp', N'Software', N'<root><row ID="10" ItemName="WebApp" ItemDescription="desc" DisplayID="4962" /></root>'), 
(12, N'WebApp', N'Software', N'<root><row ID="12" ItemName="WebApp" ItemDescription="desc" DisplayID="5687" /></root>'), 
(11, N'CRMapp', N'CRM', N'<root><row ID="11" ItemName="CRMapp" ItemDescription="desc" DisplayID="823678" /></root>') 

-- that table will store data for script generating 
DECLARE @tables TABLE (
    ID int, 
    TableName nvarchar(100), 
    ColumnName sysname, 
    ColumnValue nvarchar(max) 
) 
--here we parse XML to get column names and data 
INSERT INTO @tables 
SELECT i.ID, 
     i.ItemClass as TableName, 
     CAST(t.c.query('local-name(.)') AS nvarchar(255)) AS ColumnName, 
     t.c.value('.', 'nvarchar(max)') ColumnValue 
FROM @items i 
CROSS APPLY Details.nodes('//@*') as t(c) 
-- count tables 
SELECT @n = COUNT(DISTINCT TableName) 
FROM @tables 

-- here we go! 
WHILE @n > @i 
BEGIN 
    -- select some table 
    SELECT TOP 1 @tableName = TableName 
    FROM @tables 
    -- in this CTE we get column names in order 
    ;WITH tables_ AS (
     SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) as rn, 
       ColumnName 
     FROM @tables 
     WHERE TableName = @tableName  
    ) 


    -- here we build the create part 
    SELECT @query = N'CREATE TABLE ' + QUOTENAME(@tableName) + '(' 
    + 
    STUFF((
     SELECT N','+ QUOTENAME(ColumnName) +' nvarchar(max)' 
     FROM tables_ 
     GROUP BY rn,ColumnName 
     ORDER BY rn 
     FOR XML PATH('')),1,1,'') 
    +'); 
INSERT INTO ' + QUOTENAME(@tableName) +' VALUES' 
    -- here comes data 
    ;WITH cte AS (
     SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) as rn, 
       ID, 
       ColumnValue 
     FROM @tables 
     WHERE TableName = @tableName 
    ) 

    SELECT @query = @query + STUFF((
    SELECT ',('''+ [1] + ''',''' +[2] + ''',''' +[3] + ''',''' +[4]+''')' 
    FROM cte 
    PIVOT (max (ColumnValue) for rn in ([1],[2],[3],[4])) as bb 
    FOR XML PATH('')),1,1,''); 
    -- print query 
    PRINT @query 
    ---- execute query (first runt this script to print!) 
    --EXEC (@query) 

    SET @i+=1 
    SET @query = N'' 

    DELETE FROM @tables 
    WHERE TableName = @tableName 
END 

,將產生(和執行)的腳本,如:

CREATE TABLE [Software]([ID] nvarchar(max),[ItemName] nvarchar(max),[ItemDescription] nvarchar(max),[DisplayID] nvarchar(max)); 
INSERT INTO [Software] VALUES('10','WebApp','desc','4962'),('12','WebApp','desc','5687') 

CREATE TABLE [CRM]([ID] nvarchar(max),[ItemName] nvarchar(max),[ItemDescription] nvarchar(max),[DisplayID] nvarchar(max)); 
INSERT INTO [CRM] VALUES('11','CRMapp','desc','823678') 

您可以添加檢查,如果表已經存在。還有一些邏輯可以爲表格列獲取正確的數據類型。也許XML中可能有4個以上的屬性。

0

您可以使用EXECUTE(@Script)功能,並通過任何類型的腳本成其爲字符串。像:

EXECUTE('Create table my_table(id int)') 

所以只需遍歷查詢並將所需的任何腳本傳遞到EXECUTE。

+0

感謝您的幫助,我在sql中有點幼稚:你能解釋一下在問題中使用示例嗎?我可以嘗試使用示例代碼構建它。 –

+0

那麼,這裏是你如何創建一個[光標](https://docs.microsoft.com/en-us/sql/t-sql/language-elements/declare-cursor-transact-sql),它應該選擇一切從你的表和每一行執行2個操作:創建表和插入行。你有這個XML已經解析了嗎?如果是,比第一個查詢應該是:execute('create table'+ ItemClass +'('+%列的列表%+')') - 列表您從xml列中獲得的列。類似的方式你形成插入查詢。 – Alex

1

下面的代碼片段應該可以幫助您實現目標。

  -- Lets build the table  
      IF OBJECT_ID(N'dbo.Rajesh', N'U') IS NULL 
      BEGIN 
          CREATE TABLE Rajesh 
          (    
          ItemIdentifer varchar(100), 
          ItemClasses varchar(100) 
          ) 
      END 
      -- Insert the data 
         insert into Rajesh values ('Item1','Software') 
         insert into Rajesh values ('Item1','CRM') 
      -- Since we need to to loop all the rows and I was not sure if the intitial table has any identity column , we need the indentity column as we will use that 
      -- while looping . You can always use cusrsor , i have used this . 
      IF OBJECT_ID(N'dbo.Temp', N'U') IS NULL  
      BEGIN 
          CREATE TABLE Temp 
          ( 
          id int identity(1,1),   
          ItemIdentifer varchar(100), 
          ItemClasses varchar(100) 
          ) 
      END 
         INSERT INTO Temp (ItemIdentifer,ItemClasses) SELECT ItemIdentifer,ItemClasses FROM Rajesh 
         DECLARE @MAXiD INT 
         DECLARE @iD INT 
         SELECT @ID = 1 
         DECLARE @COMMANDSTRING VARCHAR(200) 
         DECLARE @ItemClasses VARCHAR(200) 
         SELECT @MAXiD =MAX(ID) FROM TEMP 

         WHILE (@Id <= @MAXiD) 
          BEGIN 
           SELECT @ItemClasses = 'DBO.'+ItemClasses FROM TEMP WHERE ID = @ID  
           -- As I am unaware of the table staructire for the itemclasses and just took something , please update this accordingly    
           SELECT @COMMANDSTRING = ' IF OBJECT_ID(N'''[email protected]+''', N''U'') IS NULL BEGIN CREATE TABLE '[email protected]+' ( ItemIdentifer varchar(100),ItemClasses varchar(100)) END '    
           EXEC (@COMMANDSTRING)    
           SELECT @Id = @Id +1 
          END