2012-02-07 155 views
0

我正在使用SQL Server 2008,並且需要製作一個列的公共列表。我知道如何去做,但我需要這段時間,而我使用分析功能,我的意思是我不想使用group by子句。 由於我也將選擇在外部查詢中的記錄 「其中ROW_NUM = 1SQL逗號分隔列表中的分析函數列表

下面是查詢:

SELECT UserId 
     ,ProductList 
     ,Value 
    FROM 
    (
SELECT p.UserId 
    ,p.Value 
    , ROW_NUMBER()OVER (PARTITION BY p.UserId ORDER BY p.RecordCreateDate asc) AS 'row_num' 
    --here I need a solution OVER (PARTITION BY p.UserId) AS 'ProductList' 
    FROM Products p 
     INNER JOIN 
     Users u 
     ON p.UserId = u.Id 
     ) result 
WHERE result.row_num = 1 

用戶數據:

Id  Name  .... 
1  John 
2  Anton 
3  Craig 

產品數據:

Id  UserId  Name  RecordCreateDate Value 
1   1   a   21.12.2012  10 
2   1   b   11.12.2012  20 
3   1   c   01.12.2012  30 
4   2   e   05.12.2012  40 
5   2   f   17.12.2012  50 
6   3   d   21.12.2012  60 
7   3   i   31.12.2012  70 

我需要一個結果如:

UserId  ProductList  Value 
    1   a,b,c   30 
    2    e,f   40 
    3    d,i   60 

感謝您的幫助

+0

可能重複(HTTP:/ /stackoverflow.com/questions/6603319/concatenate-values-based-on-id) – 2012-02-07 17:46:01

+1

你沒有明白,我不想用group by clause – Mehmet 2012-02-07 17:52:32

+1

你要求的結果對我來說沒有意義。 row_number()如何生效?你如何期待有任何情況下row_number <> 1的任何用戶ID?您能否顯示樣本數據和期望的結果(包括允許您的「where row_num = 1」要求有意義的結果?我沒有「明白」,因爲您沒有足夠的解釋。我沒有看到row_num在你的「我需要一個結果如:」部分,所以我不知道你在每一行row_num是什麼,你也確定UserId和RecordCreatedDate來自產品表? – 2012-02-07 17:52:35

回答

1

只是爲了保持完整性。刪除實際解決方案的#符號。

SET NOCOUNT ON; 

CREATE TABLE #users 
(
    Id INT, 
    Name VARCHAR(32) 
); 

INSERT #users VALUES 
(1,'John'), 
(2,'Anton'), 
(3,'Craig'); 

CREATE TABLE #products 
(
    Id INT, 
    UserId INT, 
    Name VARCHAR(32), 
    RecordCreateDate DATE, 
    Value INT 
); 

INSERT #products VALUES 
(1,1,'a','2012-12-21',10), 
(2,1,'b','2012-12-11',20), 
(3,1,'c','2012-12-01',30), 
(4,2,'e','2012-12-05',40), 
(5,2,'f','2012-12-17',50), 
(6,3,'d','2012-12-21',60), 
(7,3,'i','2012-12-31',70); 

查詢:

;WITH x AS 
(
    SELECT UserId, Value, 
     row_num = ROW_NUMBER() OVER 
     (
       PARTITION BY UserId 
       ORDER BY RecordCreateDate 
     ) 
     FROM #products 
) 
SELECT 
    x.UserId, 
    u.Name, 
    ProductList = STUFF((
    SELECT ',' + Name 
     FROM #Products AS p 
     WHERE p.UserId = x.UserId 
     FOR XML PATH(''), TYPE).value('.', 'varchar(max)'),1,1,''), 
    x.Value 
FROM x 
INNER JOIN #users AS u 
ON x.UserId = u.Id 
WHERE x.row_num = 1; 

然後清理:

DROP TABLE #users, #products; 

結果:

UserId Name ProductList Value 
1  John a,b,c  30 
2  Anton e,f   40 
3  Craig d,i   60 
[基於ID串聯值]的
+1

謝謝。我看不到用戶表,我需要在CTE查詢後使用(加入)嗎? – Mehmet 2012-02-07 18:36:07

+1

你需要從Users表中得到什麼?您希望的結果中沒有任何內容表明該連接需要任何內容​​。您的問題是否還有一些信息丟失? – 2012-02-07 18:37:27

+0

感謝您的回答,它按我的需要運作。非常感謝! – Mehmet 2012-02-07 18:44:29

1

我不知道你問的是什麼開始,但是這會給你所要求的輸出

SELECT UserId, 
    STUFF((SELECT ',' + ProductName from Products p WHERE p.UserID = u.UserID FOR XML PATH('')), 1, 1, '') as ProductList 
FROM Users u 
+1

他似乎需要在那裏ROW_NUM還有,我想代表每個用戶創建的最早的產品。但用UserID分區,我不明白他爲每個用戶ID如何獲得除1以外的任何內容。 – 2012-02-07 17:58:46

3

既然你要過濾在row_num = 1上,您需要將您的查詢放入CTE中或包含Products中額外列的類似內容中。然後,您可以使用for XML路徑技巧在外部查詢中構建逗號分隔的字符串,而無需使用group by。

;WITH C as 
(
    SELECT p.UserId 
     , ROW_NUMBER()OVER (PARTITION BY p.UserId ORDER BY p.RecordCreateDate asc) AS 'row_num' 
     --, Some other fields from Products 
    FROM Products p 
     INNER JOIN 
     Users u 
     ON p.UserId = u.Id 
) 
SELECT UserId, 
     --, Some other fields from Products 
     --, Build the concatenated list here using for xml path() 
FROM C 
WHERE C.row_num = 1 
+0

非常好的解決方案! – msmucker0527 2012-02-07 18:17:42

+0

謝謝。我會嘗試,並讓你知道 – Mehmet 2012-02-07 18:24:37