2016-12-09 22 views
1

我們有一個項目,我們應該爲用戶提供可能將自定義列添加到各個表的項目。具有動態(未知)列數的T-SQL查詢

編輯:這些是2表,而不是一個。

**Products** 
ProductId 
Name 
Price 
Date 
UserId 

**ProductsCustomColumns** 
ProductId 
ColumnName 
ColumnValue 

編輯:請注意,動態列被記錄爲值,我們不知道這些的個性化......它可以是0或200或任何。

下面是一個例子: enter image description here 現在,當我們詢問,我們要顯示所有的預定義欄,並在他們之後所有的自定義列的產品表。 顯然,每個用戶可以擁有自己數量的包含值和名稱的列。

SELECT *, (and the custom columns) FROM Products WHERE UserId = 3 AND ProductId = 1 

這裏有2個問題:

  1. 請問這是從性能的角度很好的解決方案或有解決動態列要求更好的辦法?

  2. 如何創建一個查詢,可以讀取ProductsCustomColumns所有記錄在給定userIdproductId和追加記錄來查詢列?

謝謝。

+0

是ProductsCustomColumns是一個單獨的表嗎? –

+0

是的,單獨的桌子。 –

回答

2

你需要編寫動態查詢

DECLARE @COLUMNS VARCHAR(MAX)='', @QRY VARCHAR(MAX); 

SELECT @COLUMNS = @COLUMNS +COLUMN_NAME +',' FROM 
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='Products' 

SELECT @COLUMNS =SUBSTRING (@COLUMNS,1 ,LEN(@COLUMNS)-1) 

SELECT @QRY ='SELECT '[email protected] + ' FROM Products WHERE UserId = 3 AND ProductId = 1' 
EXEC (@QRY) 

編輯:從您的評論&編輯問題

模式我假設你的問題

CREATE TABLE Products (
ProductId INT, 
Name VARCHAR(250), 
Price DECIMAL(18,2), 
DateS DATETIME, 
UserId INT) 

INSERT INTO Products 
SELECT 1,'Oil Product', 2000, GETDATE(), 3 
UNION ALL 
SELECT 2,'Amway', 600, GETDATE(), 2 
UNION ALL 
SELECT 3,'Thermal', 5000, GETDATE(), 1 
UNION ALL 
SELECT 4,'Oil Product', 500, GETDATE(), 4 



CREATE TABLE ProductsCustomColumns 
(
ProductId INT , 
ColumnName VARCHAR(200), 
ColumnValue VARCHAR(15)) 

INSERT INTO ProductsCustomColumns 
SELECT 1, 'Licence_No', '1545' 
UNION ALL 
SELECT 1, 'Location ', 'Atlanta' 
UNION ALL 
SELECT 2, 'Qty ', '5' 
UNION ALL 
SELECT 3, 'Gross', '80000' 

現在動態代碼放在這裏

DECLARE @COLUMN_PCC VARCHAR(MAX)='', @PRODUCT_ID INT=1,@USER_ID INT=3, @QRY VARCHAR(MAX) ; 

--preparing Custom Column Name List with comma ',' 
SELECT @COLUMN_PCC = @COLUMN_PCC+ [COLUMNNAME] +',' FROM ProductsCustomColumns 
WHERE ProductId= @PRODUCT_ID 
SELECT @COLUMN_PCC =SUBSTRING(@COLUMN_PCC,1,LEN(@COLUMN_PCC)-1) 


--Preparing Dynamic Query 
SELECT @QRY =' SELECT P.*, AV.* FROM Products P 
INNER JOIN 
(
SELECT * FROM (
SELECT * FROM ProductsCustomColumns WHERE ProductId= '+CAST(@PRODUCT_ID AS VARCHAR(50))+' 
) 
AS A 
PIVOT 
(
MAX (COLUMNVALUE) 
FOR [COLUMNNAME] IN ('[email protected]_PCC +') 
)AS PVT 
)AS AV ON P.ProductId= AV.ProductId 
AND P.UserId='++CAST(@USER_ID AS VARCHAR(50))+' 
' 

EXEC (@QRY) 

,其結果將是

+-----------+-------------+---------+-------------------------+--------+-----------+------------+----------+ 
| ProductId | Name  | Price |   DateS   | UserId | ProductId | Licence_No | Location | 
+-----------+-------------+---------+-------------------------+--------+-----------+------------+----------+ 
|   1 | Oil Product | 2000.00 | 2016-12-09 18:06:24.090 |  3 |   1 |  1545 | Atlanta | 
+-----------+-------------+---------+-------------------------+--------+-----------+------------+----------+ 
+0

動態列不來自另一個表列,它們是第二個表中的記錄。 –

+0

@st_stefanov請檢查現在編輯的答案。 –

+0

看起來不可思議,讓我試試吧! –

0

你需要動態SQL沒有其他辦法可以做到這一點

DECLARE @sql  VARCHAR(max), 
     @cust_col VARCHAR(max) 

SET @cust_col = (SELECT Quotename(CustomColumns) + ',' 
       FROM ProductsCustomColumns 
       FOR xml path('')) 

SELECT @cust_col = LEFT(@cust_col, Len(@cust_col) - 1) 

SET @sql = 'SELECT *, ' + @cust_col + ' FROM Products WHERE UserId = 3 AND ProductId = 1' 

EXEC (@sql) 
+0

當我運行它時,它顯示錯誤:消息207,級別16,狀態1,行1 無效的列名稱'Comment1'。 注意:Comment1是CustomColumn中的值。 –

1

總的來說這是一個非常糟糕的主意,在主表中的其它列添加自定義的數據。試想一下使用這個的100個客戶。他們都有不同的表格模式,你想爲他們寫一個更新腳本?

這是一個痛苦的脖子,如果你必須處理事先不知道結構的結果集!

您有幾種選擇:

  • 添加XML類型的一列。優點:結果集已修復。您只需要一個客戶特定的規則,即如何解釋XML。你可以用內聯表值函數來解決這個問題。傳入XML並返回派生表。與CROSS APPLY調用此,你出來......

  • 添加一個新表在客戶和關鍵值對

  • 如果附加數據不完全一樣,有的列添加到您的主表爲SPARSE

+0

其實這些是2張桌子。 –

+0

而且我們也在考慮預定義的大量列...... –