SQL:使用桥 table 和 return 感兴趣列的串联列表在维度上加入事实

SQL: Join fact on dimension using bridge table and return concatenated list for column of interest

我想将多个维度 table 加入一个事实 table。但是,我不想 returning 所有结果,而是想避免一对多关系结果。相反,我只想访问一个 table 中的 一些 数据,将其所有发现连接起来,并将它们 return 到一个列中,以便每个事实 1 行的预期结果仍然存在。我不希望结果中存在一对多关系。

如果我将此答案 How to concatenate text from multiple rows into a single text string in SQL Server 与其他感兴趣的列配对,我会收到一条错误消息:is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

-- sample values
-- bridge
dim2Key, groupKey
1,          1
2,          1
3,          1
4,          2

-- dim2
dim2Key, attributeOne
1,      'A'
2,      'B'
3,      'C'
4,      'A'

-- dim1
dim1Key, attributeTwo, attributeThree,
1,      35,                  'val1'      
2,      25,                  'val2'   
3,      45,                  'val3'   
4,      55,                  'val1'   

-- fact1
dim1Key, factvalue1, groupKey,
1,        5,            1
2,        25,           1
3,        55,           -1
4,        99,           2


-- expected values
-- fact1
dim1Key, factvalue1, groupKey, attributeTwo, attributeThree, attributeOne
1,          5,          1,          35,         'val1',         'A, B, C'
...
4,          99,         2,           55,         'val1',            'A'

目前还不清楚您的架构和连接应该是什么,但您似乎想要聚合 dim2 每行 fact1

您可以在相关子查询中聚合 dim2。将其放在 APPLY 中通常更好,但您也可以直接将其放在 SELECT

SELECT
  fact1.dim1Key,
  fact1.factvalue1,
  fact1.groupKey,
  dim1.attributeTwo,
  dim1.attributeThree,
  dim2.attributeOne
FROM fact1
JOIN dim1 ON dim1.dim1key = fact1.dim1key
CROSS APPLY (
    SELECT attributeOne = STRING_AGG(dim2.attributeOne, ', ')
    FROM bridge b
    JOIN dim2 ON dim2.dim2key = b.dim2key
    WHERE b.groupKey = fact1.groupKey
) dim2

如果您无法访问 SQL 版本中的 STRING_AGG 函数,您可以使用 FOR XML PATH 来实现相同的目的。

    CREATE TABLE #bridge (dim2Key int, groupKey int)
    INSERT  #bridge (dim2Key, groupKey) 
    VALUES (1, 1)
    ,(2, 1)
    ,(3, 1)
    ,(4, 2)

    CREATE TABLE #dim2 (dim2Key int, attributeOne varchar(5))
    INSERT  #dim2 (dim2Key, attributeOne)
    VALUES (1, 'A')
    ,(2, 'B')
    ,(3, 'C')
    ,(4, 'A')

    CREATE TABLE #dim1 (dim1Key int, attributeTwo int, attributeThree varchar(5))
    INSERT #dim1 (dim1Key, attributeTwo, attributeThree)
    VALUES (1, 35,   'val1') 
    ,(2, 25,   'val2')   
    ,(3, 45,   'val3')   
    ,(4, 55,   'val1')   

    CREATE TABLE #fact1 (dim1Key int, factvalue1 int, groupKey int)
    INSERT #fact1 (dim1Key, factvalue1, groupKey)
    VALUES (1,   5,  1)
    ,(2,   25, 1)
    ,(3,   55, -1)
    ,(4,   99, 2)
    GO
    

    ;WITH pvt (groupKey, attributeOne)
    AS 
    (
        SELECT b.groupKey, d2.attributeOne 
        FROM #dim2 d2
        JOIN #bridge b
        ON d2.dim2Key = b.dim2Key
    )
    , dim2 AS
    (
        SELECT DISTINCT a.groupKey
        ,LEFT(r.attributeOne.value('text()[1]','nvarchar(max)') , LEN(r.attributeOne.value('text()[1]','nvarchar(max)'))-1) attributeOne 
        FROM pvt a
        CROSS APPLY
        (
            SELECT attributeOne + ', '
            FROM pvt r
            WHERE a.groupKey = r.groupKey
            FOR XML PATH(''), TYPE
        ) r (attributeOne)
    )



    SELECT f1.dim1Key, factvalue1, f1.groupKey, attributeTwo, attributeThree, attributeOne 
    FROM #fact1 f1
    LEFT JOIN #dim1 d1
    ON f1.dim1Key = d1.dim1Key
    LEFT JOIN dim2 d2
    ON f1.groupKey = d2.groupKey