SQL Server 2008 - 查找艺术品的位置
SQL Server 2008 - Find Locations for Artwork
考虑以下 table 和 SQL Server 2008 数据库中的数据:
CREATE TABLE sponsorships
(
sponsorshipID INT NOT NULL PRIMARY KEY IDENTITY,
sponsorshipLocationID INT NOT NULL,
sponsorshipArtworkID INT NOT NULL
);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (1, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (1, 2);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (2, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (2, 2);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (3, 3);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (4, 3);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (5, 4);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (6, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (7, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (7, 3);
SELECT *
FROM sponsorships s
ORDER BY s.sponsorshipLocationID, s.sponsorshipArtworkID
如何生成以下输出?
CREATE TABLE sponGroups
(
rank INT,
sponsorshipID INT,
sponsorshipLocationID INT,
sponsorshipArtworkID INT
);
INSERT INTO sponGroups VALUES (1, 1, 1, 1);
INSERT INTO sponGroups VALUES (1, 2, 1, 2);
INSERT INTO sponGroups VALUES (1, 3, 2, 1);
INSERT INTO sponGroups VALUES (1, 4, 2, 2);
INSERT INTO sponGroups VALUES (2, 5, 3, 3);
INSERT INTO sponGroups VALUES (2, 6, 4, 3);
INSERT INTO sponGroups VALUES (3, 7, 5, 4);
INSERT INTO sponGroups VALUES (4, 8, 6, 1);
INSERT INTO sponGroups VALUES (5, 9, 7, 1);
INSERT INTO sponGroups VALUES (5, 10, 7, 3);
SELECT *
FROM sponGroups sg
ORDER BY sg.rank, sg.sponsorshipID, sg.sponsorshipLocationID, sg.sponsorshipArtworkID
Fiddle 可用,here.
说明
艺术作品展示在不同的位置。一些位置安装了双面图稿(例如 windows),而一些位置则安装了单面图稿(例如墙壁)。例如,位置 1 的图稿是双面的——它具有 sponsorshipArtworkID 1 和 2——而位置 5 的图稿是单面的 (sponsorshipArtworkID 4)。
为了打印和安装目的,我需要一个查询来生成每件艺术品,无论是单面还是双面,以及与该作品相关的所有位置。 (在上面链接的 fiddle 中引用所需的输出。)因此,例如,我需要告诉打印机:
- 打印双面图 (1,2) 并将其安装在位置 (1,2);
- 打印单面图稿 (3) 并将其安装在位置 (3,4);
- 打印单面图(4)并安装到位置(5);
- 打印单面图 (1) 并将其安装在位置 (6);
- 打印双面图 (1,3) 并将其安装在位置 (7)。
请注意,艺术有时会被重复使用,因此 sponsorshipArtworkID 1 用于单面和双面位置。
我曾尝试使用 DENSE_RANK()、递归 CTE 和集合除法来解决这个问题,但到目前为止还没有成功。在此先感谢您的帮助。
可能看起来有点丑,但是思路很简单
首先按 sponsorshipLocationID
分组,并使用关联的 sponsorshipArtworkID
.
列表构建一个逗号分隔的字符串
然后根据这个以逗号分隔的艺术作品 ID 字符串计算密集排名。
在下面的查询中,我使用 FOR XML
来连接字符串。这不是唯一的方法。有编写好的快速 CLR 函数可以做到这一点。
我建议 运行 下面的查询,逐个 CTE,并检查中间结果以了解它是如何工作的。
示例数据
DECLARE @sponsorships TABLE
(
sponsorshipID INT NOT NULL PRIMARY KEY IDENTITY,
sponsorshipLocationID INT NOT NULL,
sponsorshipArtworkID INT NOT NULL
);
INSERT INTO @sponsorships (sponsorshipLocationID, sponsorshipArtworkID) VALUES
(1, 1),
(1, 2),
(2, 1),
(2, 2),
(3, 3),
(4, 3),
(5, 4),
(6, 1),
(7, 1),
(7, 3);
查询
WITH
CTE_Locations
AS
(
SELECT
sponsorshipLocationID
FROM
@sponsorships AS S
GROUP BY
sponsorshipLocationID
)
,CTE_Artworks
AS
(
SELECT
CTE_Locations.sponsorshipLocationID
,CA_Data.Artwork_Value
FROM
CTE_Locations
CROSS APPLY
(
SELECT CAST(S.sponsorshipArtworkID AS varchar(10)) + ','
FROM
@sponsorships AS S
WHERE
S.sponsorshipLocationID = CTE_Locations.sponsorshipLocationID
ORDER BY
S.sponsorshipArtworkID
FOR XML PATH(''), TYPE
) AS CA_XML(XML_Value)
CROSS APPLY
(
SELECT CA_XML.XML_Value.value('.', 'NVARCHAR(MAX)')
) AS CA_Data(Artwork_Value)
)
,CTE_Rank
AS
(
SELECT
sponsorshipLocationID
,Artwork_Value
,DENSE_RANK() OVER (ORDER BY Artwork_Value) AS r
FROM CTE_Artworks
)
SELECT
CTE_Rank.r
,S.sponsorshipID
,CTE_Rank.sponsorshipLocationID
,S.sponsorshipArtworkID
FROM
CTE_Rank
INNER JOIN @sponsorships AS S
ON S.sponsorshipLocationID = CTE_Rank.sponsorshipLocationID
ORDER BY
S.sponsorshipID
;
结果
+---+---------------+-----------------------+----------------------+
| r | sponsorshipID | sponsorshipLocationID | sponsorshipArtworkID |
+---+---------------+-----------------------+----------------------+
| 2 | 1 | 1 | 1 |
| 2 | 2 | 1 | 2 |
| 2 | 3 | 2 | 1 |
| 2 | 4 | 2 | 2 |
| 4 | 5 | 3 | 3 |
| 4 | 6 | 4 | 3 |
| 5 | 7 | 5 | 4 |
| 1 | 8 | 6 | 1 |
| 3 | 9 | 7 | 1 |
| 3 | 10 | 7 | 3 |
+---+---------------+-----------------------+----------------------+
rank 的实际值与您的预期结果不完全相同,但它们对行进行了正确分组。
考虑以下 table 和 SQL Server 2008 数据库中的数据:
CREATE TABLE sponsorships
(
sponsorshipID INT NOT NULL PRIMARY KEY IDENTITY,
sponsorshipLocationID INT NOT NULL,
sponsorshipArtworkID INT NOT NULL
);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (1, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (1, 2);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (2, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (2, 2);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (3, 3);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (4, 3);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (5, 4);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (6, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (7, 1);
INSERT INTO sponsorships (sponsorshipLocationID, sponsorshipArtworkID)
VALUES (7, 3);
SELECT *
FROM sponsorships s
ORDER BY s.sponsorshipLocationID, s.sponsorshipArtworkID
如何生成以下输出?
CREATE TABLE sponGroups
(
rank INT,
sponsorshipID INT,
sponsorshipLocationID INT,
sponsorshipArtworkID INT
);
INSERT INTO sponGroups VALUES (1, 1, 1, 1);
INSERT INTO sponGroups VALUES (1, 2, 1, 2);
INSERT INTO sponGroups VALUES (1, 3, 2, 1);
INSERT INTO sponGroups VALUES (1, 4, 2, 2);
INSERT INTO sponGroups VALUES (2, 5, 3, 3);
INSERT INTO sponGroups VALUES (2, 6, 4, 3);
INSERT INTO sponGroups VALUES (3, 7, 5, 4);
INSERT INTO sponGroups VALUES (4, 8, 6, 1);
INSERT INTO sponGroups VALUES (5, 9, 7, 1);
INSERT INTO sponGroups VALUES (5, 10, 7, 3);
SELECT *
FROM sponGroups sg
ORDER BY sg.rank, sg.sponsorshipID, sg.sponsorshipLocationID, sg.sponsorshipArtworkID
Fiddle 可用,here.
说明
艺术作品展示在不同的位置。一些位置安装了双面图稿(例如 windows),而一些位置则安装了单面图稿(例如墙壁)。例如,位置 1 的图稿是双面的——它具有 sponsorshipArtworkID 1 和 2——而位置 5 的图稿是单面的 (sponsorshipArtworkID 4)。
为了打印和安装目的,我需要一个查询来生成每件艺术品,无论是单面还是双面,以及与该作品相关的所有位置。 (在上面链接的 fiddle 中引用所需的输出。)因此,例如,我需要告诉打印机:
- 打印双面图 (1,2) 并将其安装在位置 (1,2);
- 打印单面图稿 (3) 并将其安装在位置 (3,4);
- 打印单面图(4)并安装到位置(5);
- 打印单面图 (1) 并将其安装在位置 (6);
- 打印双面图 (1,3) 并将其安装在位置 (7)。
请注意,艺术有时会被重复使用,因此 sponsorshipArtworkID 1 用于单面和双面位置。
我曾尝试使用 DENSE_RANK()、递归 CTE 和集合除法来解决这个问题,但到目前为止还没有成功。在此先感谢您的帮助。
可能看起来有点丑,但是思路很简单
首先按 sponsorshipLocationID
分组,并使用关联的 sponsorshipArtworkID
.
然后根据这个以逗号分隔的艺术作品 ID 字符串计算密集排名。
在下面的查询中,我使用 FOR XML
来连接字符串。这不是唯一的方法。有编写好的快速 CLR 函数可以做到这一点。
我建议 运行 下面的查询,逐个 CTE,并检查中间结果以了解它是如何工作的。
示例数据
DECLARE @sponsorships TABLE
(
sponsorshipID INT NOT NULL PRIMARY KEY IDENTITY,
sponsorshipLocationID INT NOT NULL,
sponsorshipArtworkID INT NOT NULL
);
INSERT INTO @sponsorships (sponsorshipLocationID, sponsorshipArtworkID) VALUES
(1, 1),
(1, 2),
(2, 1),
(2, 2),
(3, 3),
(4, 3),
(5, 4),
(6, 1),
(7, 1),
(7, 3);
查询
WITH
CTE_Locations
AS
(
SELECT
sponsorshipLocationID
FROM
@sponsorships AS S
GROUP BY
sponsorshipLocationID
)
,CTE_Artworks
AS
(
SELECT
CTE_Locations.sponsorshipLocationID
,CA_Data.Artwork_Value
FROM
CTE_Locations
CROSS APPLY
(
SELECT CAST(S.sponsorshipArtworkID AS varchar(10)) + ','
FROM
@sponsorships AS S
WHERE
S.sponsorshipLocationID = CTE_Locations.sponsorshipLocationID
ORDER BY
S.sponsorshipArtworkID
FOR XML PATH(''), TYPE
) AS CA_XML(XML_Value)
CROSS APPLY
(
SELECT CA_XML.XML_Value.value('.', 'NVARCHAR(MAX)')
) AS CA_Data(Artwork_Value)
)
,CTE_Rank
AS
(
SELECT
sponsorshipLocationID
,Artwork_Value
,DENSE_RANK() OVER (ORDER BY Artwork_Value) AS r
FROM CTE_Artworks
)
SELECT
CTE_Rank.r
,S.sponsorshipID
,CTE_Rank.sponsorshipLocationID
,S.sponsorshipArtworkID
FROM
CTE_Rank
INNER JOIN @sponsorships AS S
ON S.sponsorshipLocationID = CTE_Rank.sponsorshipLocationID
ORDER BY
S.sponsorshipID
;
结果
+---+---------------+-----------------------+----------------------+
| r | sponsorshipID | sponsorshipLocationID | sponsorshipArtworkID |
+---+---------------+-----------------------+----------------------+
| 2 | 1 | 1 | 1 |
| 2 | 2 | 1 | 2 |
| 2 | 3 | 2 | 1 |
| 2 | 4 | 2 | 2 |
| 4 | 5 | 3 | 3 |
| 4 | 6 | 4 | 3 |
| 5 | 7 | 5 | 4 |
| 1 | 8 | 6 | 1 |
| 3 | 9 | 7 | 1 |
| 3 | 10 | 7 | 3 |
+---+---------------+-----------------------+----------------------+
rank 的实际值与您的预期结果不完全相同,但它们对行进行了正确分组。