SQL:从视图中聚合函数选取的行中获取列
SQL: Taking Column From a Row Picked By Aggregate Function in View
我有三个 SQL tables:Release
(表示电影的发行),Media
(表示那些版本;即对于 Blu-ray/DVD 组合,Media
中将有两行,一张蓝光和一张 DVD,指向 Release
) 和 [=21 中的同一行=](定义蓝光、DVD、VHS 等)。 Release
/Media
和 MediaType
/Media
是一对多的关系,Media
在两者的 "many" 一侧关系。我有一个 Release
、vRelease
的视图,其中包含聚合函数,例如显示与该版本关联的媒体数量的 COUNT
。到目前为止,这是我对该视图的看法:
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
,MIN(dbo.MediaType.Name) AS FirstMediaType
FROM dbo.MediaType INNER JOIN
dbo.Media ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID RIGHT OUTER JOIN
dbo.Release ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
您会注意到我还包含了另外两个聚合列:FirstMediaID
获取与 Media
table 中最先出现的版本关联的媒体 ID (即,如果一个发行版有两张与之相关联的 DVD,它会获得一张 ID 值较低的 DVD)。这个专栏本身没有用;然后,我想做的是依次获取与 Media
相关联的 MediaType
。换句话说,我想要一个显示第一个 Media
的 MediaType
的列,它附加到每个 Release
。之后的列 FirstMediaType
应该这样做,但它却在与 Release
关联的所有 Media
中获取 MediaType
并选择一个按字母顺序排列 - 这意味着 Blu-ray 将始终优先于 DVD(这很好),但音频 CD 将始终优先于其他所有内容(这不好)。
如何获取此视图中的 FirstMediaType
列以获取 FirstMediaID
中标识的媒体的 MediaType
?
更新:这里是 tables,它们的列和一些示例行。
来自Release
的一对:
+-----------+----------------------------------------+-------+-------------+---------+
| ReleaseID | Name | Owner | Compilation | LentOut |
+-----------+----------------------------------------+-------+-------------+---------+
| 2 | Alice in Wonderland | NULL | 0 | 0 |
| 6 | 4 Film Favorites - Family Comedies | NULL | 1 | 0 |
| 8 | Aladdin | NULL | 0 | 0 |
| 463 | Harry Potter and the Half-Blood Prince | NULL | 0 | 1 |
| 534 | Spirited Away | Ryan | 0 | 0 |
| 571 | The Original Christmas Classics | NULL | 1 | 0 |
+-----------+----------------------------------------+-------+-------------+---------+
Compilation
表示发行版中包含不止一部电影。
Media
中对应条目:
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
| MediaID | MediaTypeID | Name | ReleaseID |
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
| 2 | 2 | Movie | 2 |
| 3 | 1 | Movie | 2 |
| 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 13 | 1 | Funky Monkey; Osmosis Jones | 6 |
| 17 | 3 | Movie | 8 |
| 620 | 1 | Movie | 463 |
| 726 | 1 | Movie | 534 |
| 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
| 808 | 1 | Frosty the Snowman; Frosty Returns | 571 |
| 809 | 1 | Santa Claus is Comin' to Town!; Mr. Magoo's Christmas Carol; The Little Drummer Boy | 571 |
| 810 | 4 | Tracks 1-7 | 571 |
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
MediaType
中的前几名:
+-------------+--------------+
| MediaTypeID | Name |
+-------------+--------------+
| 1 | DVD Disc |
| 2 | Blu-ray Disc |
| 3 | VHS |
| 4 | Audio CD |
+-------------+--------------+
vRelease
中对应的条目应该是这样的:
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| ReleaseID | Name | Compilation | Owner | LentOut | NumberOfMedia | FirstMediaID | FirstMediaType |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| 2 | Alice in Wonderland | No | NULL | No | 2 | 2 | Blu-ray Disc |
| 6 | 4 Film Favorites - Family Comedies | Yes | NULL | No | 2 | 12 | DVD Disc |
| 8 | Aladdin | No | NULL | No | 1 | 17 | VHS |
| 463 | Harry Potter and the Half-Blood Prince | No | NULL | Yes | 1 | 620 | DVD Disc |
| 534 | Spirited Away | No | Ryan | No | 1 | 726 | DVD Disc |
| 571 | The Original Christmas Classics | Yes | NULL | No | 4 | 807 | DVD Disc |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
但实际上是这样的:
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| ReleaseID | Name | Compilation | Owner | LentOut | NumberOfMedia | FirstMediaID | FirstMediaType |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| 2 | Alice in Wonderland | No | NULL | No | 2 | 2 | Blu-ray Disc |
| 6 | 4 Film Favorites - Family Comedies | Yes | NULL | No | 2 | 12 | DVD Disc |
| 8 | Aladdin | No | NULL | No | 1 | 17 | VHS |
| 463 | Harry Potter and the Half-Blood Prince | No | NULL | Yes | 1 | 620 | DVD Disc |
| 534 | Spirited Away | No | Ryan | No | 1 | 726 | DVD Disc |
| 571 | The Original Christmas Classics | Yes | NULL | No | 4 | 807 | Audio CD |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
问题出在最后一个。
最简单的方法是在 FirstMediaId = MediaType.MediaId
上向您的 MediaType
table 添加另一个连接
;WITH data AS (
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
FROM dbo.MediaType
INNER JOIN dbo.Media
ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID
RIGHT OUTER JOIN dbo.Release
ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
)
SELECT data.ReleaseId
,data.Name
,data.Compilation
,data.Owner
,data.LentOut
,data.NumberOfMedia
,data.FirstMediaId
,MediaType.Name as FirstMediaName
FROM data
LEFT OUTER JOIN dbo.MediaType
ON data.FirstMediaId = MediaType.MediaTypeId
returns整行与"First"、"Last"、"Earliest"、"Latest"等需求相关联的一个非常方便的技术是使用row_number() over()
。这里你想要"first media type",所以它在这里是相关的。
正如您将在以下查询中看到的那样,加入 [Media] table 被替换为包含行号计算的子查询。这里我们partition by
ReleaseID和order by
MediaID,所以,对于each ReleaseID 第一行将是具有最低 MediaID 值的行。然后在这个派生的 table 的连接中添加一个额外的条件以仅考虑行号为 1.
的行
建议查询
SELECT
r.ReleaseID
, m.MediaID
, mt.MediaTypeID
, mt.name MediaName
, r.Name
, CASE
WHEN r.Compilation = 0 THEN 'No'
WHEN r.Compilation = 1 THEN 'Yes'
END AS compilation
, r.Owner
, CASE
WHEN r.LentOut = 0 THEN 'No'
WHEN r.LentOut = 1 THEN 'Yes'
END AS lentout
FROM dbo.Release r
INNER JOIN (
SELECT
Media.*
, ROW_NUMBER() OVER(PARTITION BY ReleaseID
ORDER BY MediaID) AS rn
FROM dbo.Media
) m ON r.ReleaseID = m.ReleaseID and rn = 1
INNER JOIN dbo.MediaType mt ON m.MediaTypeID = mt.MediaTypeID
结果
| ReleaseID | MediaID | MediaTypeID | MediaName | Name | compilation | Owner | lentout |
|-----------|---------|-------------|--------------|----------------------------------------|-------------|--------|---------|
| 2 | 2 | 2 | Blu-ray Disc | Alice in Wonderland | No | (null) | No |
| 6 | 12 | 1 | DVD Disc | 4 Film Favorites - Family Comedies | Yes | (null) | No |
| 8 | 17 | 3 | VHS | Aladdin | No | (null) | No |
| 463 | 620 | 1 | DVD Disc | Harry Potter and the Half-Blood Prince | No | (null) | Yes |
| 534 | 726 | 1 | DVD Disc | Spirited Away | No | Ryan | No |
| 571 | 807 | 1 | DVD Disc | The Original Christmas Classics | Yes | (null) | No |
我最终找到了一种简单的方法来做我想做的事。它不像 Used_By_Already 的答案那么花哨(据我所知,它确实有效)并且可能在某处打破了 SQL 最佳实践规则,但它更容易理解和保持——至少对我的新手来说是这样。
由于问题是试图让视图使用它在连接中计算的聚合列,我只是将两步操作拆分为两个视图。 vReleasePre
包含我在原始查询中概述的所有列,FirstMediaType
除外。 vRelease
现在只需从 vReleasePre
中获取所有列并添加 FirstMediaType
,它从末尾的连接中获取其值:LEFT OUTER JOIN dbo.vMedia ON dbo.vReleasePre.FirstMediaID = dbo.vMedia.MediaID
,其中 vMedia
是包含 Media
中所有列的视图,加上 MediaType
列(我已经有 vMedia
了)。
由于此数据库通过 Entity Framework 在 ASP.NET MVC 网络应用程序中使用,并且 EF 对数据模型将接受和不接受的内容一直很奇怪,我想一个简单但迂回的解决方案可能是我的最佳选择。
vReleasePre
:
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
FROM dbo.MediaType INNER JOIN
dbo.Media ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID RIGHT OUTER JOIN
dbo.Release ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
vRelease
:
SELECT dbo.vReleasePre.ReleaseID
,dbo.vReleasePre.Name
,dbo.vReleasePre.Compilation
,dbo.vReleasePre.Owner
,dbo.vReleasePre.LentOut
,dbo.vReleasePre.NumberOfMedia
,dbo.vMedia.MediaType
FROM dbo.vReleasePre LEFT OUTER JOIN
dbo.vMedia ON dbo.vReleasePre.FirstMediaID = dbo.vMedia.MediaID
对于新手来说,这是我使用的子查询
SELECT
ROW_NUMBER() OVER(PARTITION BY ReleaseID
ORDER BY MediaID) AS rn
, Media.*
FROM dbo.Media
这就是它的作用(参见 rn 列)
| rn | MediaID | MediaTypeID | Name | ReleaseID |
|----|---------|-------------|-------------------------------------------------------------------------------------|-----------|
| 1 | 2 | 2 | Movie | 2 |
| 2 | 3 | 1 | Movie | 2 |
| 1 | 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 2 | 13 | 1 | Funky Monkey; Osmosis Jones | 6 |
| 1 | 17 | 3 | Movie | 8 |
| 1 | 620 | 1 | Movie | 463 |
| 1 | 726 | 1 | Movie | 534 |
| 1 | 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
| 2 | 808 | 1 | Frosty the Snowman; Frosty Returns | 571 |
| 3 | 809 | 1 | Santa Claus is Comin' to Town!; Mr. Magoo's Christmas Carol; The Little Drummer Boy | 571 |
| 4 | 810 | 4 | Tracks 1-7 | 571 |
现在只保留 rn 列中有 1 的那些行:
| rn | MediaID | MediaTypeID | Name | ReleaseID |
|----|---------|-------------|-------------------------------------------------------|-----------|
| 1 | 2 | 2 | Movie | 2 |
| 1 | 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 1 | 17 | 3 | Movie | 8 |
| 1 | 620 | 1 | Movie | 463 |
| 1 | 726 | 1 | Movie | 534 |
| 1 | 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
然后加入 那些行 到 Releases 和 MediaType
宾果
=想要的结果。
不难,真的不难。您真的会想要了解这些 window 功能,因为它们可以解决大量问题。
我有三个 SQL tables:Release
(表示电影的发行),Media
(表示那些版本;即对于 Blu-ray/DVD 组合,Media
中将有两行,一张蓝光和一张 DVD,指向 Release
) 和 [=21 中的同一行=](定义蓝光、DVD、VHS 等)。 Release
/Media
和 MediaType
/Media
是一对多的关系,Media
在两者的 "many" 一侧关系。我有一个 Release
、vRelease
的视图,其中包含聚合函数,例如显示与该版本关联的媒体数量的 COUNT
。到目前为止,这是我对该视图的看法:
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
,MIN(dbo.MediaType.Name) AS FirstMediaType
FROM dbo.MediaType INNER JOIN
dbo.Media ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID RIGHT OUTER JOIN
dbo.Release ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
您会注意到我还包含了另外两个聚合列:FirstMediaID
获取与 Media
table 中最先出现的版本关联的媒体 ID (即,如果一个发行版有两张与之相关联的 DVD,它会获得一张 ID 值较低的 DVD)。这个专栏本身没有用;然后,我想做的是依次获取与 Media
相关联的 MediaType
。换句话说,我想要一个显示第一个 Media
的 MediaType
的列,它附加到每个 Release
。之后的列 FirstMediaType
应该这样做,但它却在与 Release
关联的所有 Media
中获取 MediaType
并选择一个按字母顺序排列 - 这意味着 Blu-ray 将始终优先于 DVD(这很好),但音频 CD 将始终优先于其他所有内容(这不好)。
如何获取此视图中的 FirstMediaType
列以获取 FirstMediaID
中标识的媒体的 MediaType
?
更新:这里是 tables,它们的列和一些示例行。
来自Release
的一对:
+-----------+----------------------------------------+-------+-------------+---------+
| ReleaseID | Name | Owner | Compilation | LentOut |
+-----------+----------------------------------------+-------+-------------+---------+
| 2 | Alice in Wonderland | NULL | 0 | 0 |
| 6 | 4 Film Favorites - Family Comedies | NULL | 1 | 0 |
| 8 | Aladdin | NULL | 0 | 0 |
| 463 | Harry Potter and the Half-Blood Prince | NULL | 0 | 1 |
| 534 | Spirited Away | Ryan | 0 | 0 |
| 571 | The Original Christmas Classics | NULL | 1 | 0 |
+-----------+----------------------------------------+-------+-------------+---------+
Compilation
表示发行版中包含不止一部电影。
Media
中对应条目:
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
| MediaID | MediaTypeID | Name | ReleaseID |
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
| 2 | 2 | Movie | 2 |
| 3 | 1 | Movie | 2 |
| 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 13 | 1 | Funky Monkey; Osmosis Jones | 6 |
| 17 | 3 | Movie | 8 |
| 620 | 1 | Movie | 463 |
| 726 | 1 | Movie | 534 |
| 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
| 808 | 1 | Frosty the Snowman; Frosty Returns | 571 |
| 809 | 1 | Santa Claus is Comin' to Town!; Mr. Magoo's Christmas Carol; The Little Drummer Boy | 571 |
| 810 | 4 | Tracks 1-7 | 571 |
+---------+-------------+-------------------------------------------------------------------------------------+-----------+
MediaType
中的前几名:
+-------------+--------------+
| MediaTypeID | Name |
+-------------+--------------+
| 1 | DVD Disc |
| 2 | Blu-ray Disc |
| 3 | VHS |
| 4 | Audio CD |
+-------------+--------------+
vRelease
中对应的条目应该是这样的:
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| ReleaseID | Name | Compilation | Owner | LentOut | NumberOfMedia | FirstMediaID | FirstMediaType |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| 2 | Alice in Wonderland | No | NULL | No | 2 | 2 | Blu-ray Disc |
| 6 | 4 Film Favorites - Family Comedies | Yes | NULL | No | 2 | 12 | DVD Disc |
| 8 | Aladdin | No | NULL | No | 1 | 17 | VHS |
| 463 | Harry Potter and the Half-Blood Prince | No | NULL | Yes | 1 | 620 | DVD Disc |
| 534 | Spirited Away | No | Ryan | No | 1 | 726 | DVD Disc |
| 571 | The Original Christmas Classics | Yes | NULL | No | 4 | 807 | DVD Disc |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
但实际上是这样的:
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| ReleaseID | Name | Compilation | Owner | LentOut | NumberOfMedia | FirstMediaID | FirstMediaType |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
| 2 | Alice in Wonderland | No | NULL | No | 2 | 2 | Blu-ray Disc |
| 6 | 4 Film Favorites - Family Comedies | Yes | NULL | No | 2 | 12 | DVD Disc |
| 8 | Aladdin | No | NULL | No | 1 | 17 | VHS |
| 463 | Harry Potter and the Half-Blood Prince | No | NULL | Yes | 1 | 620 | DVD Disc |
| 534 | Spirited Away | No | Ryan | No | 1 | 726 | DVD Disc |
| 571 | The Original Christmas Classics | Yes | NULL | No | 4 | 807 | Audio CD |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
问题出在最后一个。
最简单的方法是在 FirstMediaId = MediaType.MediaId
MediaType
table 添加另一个连接
;WITH data AS (
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
FROM dbo.MediaType
INNER JOIN dbo.Media
ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID
RIGHT OUTER JOIN dbo.Release
ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
)
SELECT data.ReleaseId
,data.Name
,data.Compilation
,data.Owner
,data.LentOut
,data.NumberOfMedia
,data.FirstMediaId
,MediaType.Name as FirstMediaName
FROM data
LEFT OUTER JOIN dbo.MediaType
ON data.FirstMediaId = MediaType.MediaTypeId
returns整行与"First"、"Last"、"Earliest"、"Latest"等需求相关联的一个非常方便的技术是使用row_number() over()
。这里你想要"first media type",所以它在这里是相关的。
正如您将在以下查询中看到的那样,加入 [Media] table 被替换为包含行号计算的子查询。这里我们partition by
ReleaseID和order by
MediaID,所以,对于each ReleaseID 第一行将是具有最低 MediaID 值的行。然后在这个派生的 table 的连接中添加一个额外的条件以仅考虑行号为 1.
建议查询
SELECT
r.ReleaseID
, m.MediaID
, mt.MediaTypeID
, mt.name MediaName
, r.Name
, CASE
WHEN r.Compilation = 0 THEN 'No'
WHEN r.Compilation = 1 THEN 'Yes'
END AS compilation
, r.Owner
, CASE
WHEN r.LentOut = 0 THEN 'No'
WHEN r.LentOut = 1 THEN 'Yes'
END AS lentout
FROM dbo.Release r
INNER JOIN (
SELECT
Media.*
, ROW_NUMBER() OVER(PARTITION BY ReleaseID
ORDER BY MediaID) AS rn
FROM dbo.Media
) m ON r.ReleaseID = m.ReleaseID and rn = 1
INNER JOIN dbo.MediaType mt ON m.MediaTypeID = mt.MediaTypeID
结果
| ReleaseID | MediaID | MediaTypeID | MediaName | Name | compilation | Owner | lentout |
|-----------|---------|-------------|--------------|----------------------------------------|-------------|--------|---------|
| 2 | 2 | 2 | Blu-ray Disc | Alice in Wonderland | No | (null) | No |
| 6 | 12 | 1 | DVD Disc | 4 Film Favorites - Family Comedies | Yes | (null) | No |
| 8 | 17 | 3 | VHS | Aladdin | No | (null) | No |
| 463 | 620 | 1 | DVD Disc | Harry Potter and the Half-Blood Prince | No | (null) | Yes |
| 534 | 726 | 1 | DVD Disc | Spirited Away | No | Ryan | No |
| 571 | 807 | 1 | DVD Disc | The Original Christmas Classics | Yes | (null) | No |
我最终找到了一种简单的方法来做我想做的事。它不像 Used_By_Already 的答案那么花哨(据我所知,它确实有效)并且可能在某处打破了 SQL 最佳实践规则,但它更容易理解和保持——至少对我的新手来说是这样。
由于问题是试图让视图使用它在连接中计算的聚合列,我只是将两步操作拆分为两个视图。 vReleasePre
包含我在原始查询中概述的所有列,FirstMediaType
除外。 vRelease
现在只需从 vReleasePre
中获取所有列并添加 FirstMediaType
,它从末尾的连接中获取其值:LEFT OUTER JOIN dbo.vMedia ON dbo.vReleasePre.FirstMediaID = dbo.vMedia.MediaID
,其中 vMedia
是包含 Media
中所有列的视图,加上 MediaType
列(我已经有 vMedia
了)。
由于此数据库通过 Entity Framework 在 ASP.NET MVC 网络应用程序中使用,并且 EF 对数据模型将接受和不接受的内容一直很奇怪,我想一个简单但迂回的解决方案可能是我的最佳选择。
vReleasePre
:
SELECT dbo.Release.ReleaseID
,dbo.Release.Name
,CASE WHEN Release.Compilation = 0 THEN 'No' WHEN Release.Compilation = 1 THEN 'Yes' END AS Compilation
,dbo.Release.Owner
,CASE WHEN Release.LentOut = 0 THEN 'No' WHEN Release.LentOut = 1 THEN 'Yes' END AS LentOut
,COUNT(dbo.Media.ReleaseID) AS NumberOfMedia
,MIN(dbo.Media.MediaID) AS FirstMediaID
FROM dbo.MediaType INNER JOIN
dbo.Media ON dbo.MediaType.MediaTypeID = dbo.Media.MediaTypeID RIGHT OUTER JOIN
dbo.Release ON dbo.Media.ReleaseID = dbo.Release.ReleaseID
GROUP BY dbo.Release.ReleaseID, dbo.Release.Name, dbo.Release.Compilation, dbo.Release.Owner, dbo.Release.LentOut
vRelease
:
SELECT dbo.vReleasePre.ReleaseID
,dbo.vReleasePre.Name
,dbo.vReleasePre.Compilation
,dbo.vReleasePre.Owner
,dbo.vReleasePre.LentOut
,dbo.vReleasePre.NumberOfMedia
,dbo.vMedia.MediaType
FROM dbo.vReleasePre LEFT OUTER JOIN
dbo.vMedia ON dbo.vReleasePre.FirstMediaID = dbo.vMedia.MediaID
对于新手来说,这是我使用的子查询
SELECT
ROW_NUMBER() OVER(PARTITION BY ReleaseID
ORDER BY MediaID) AS rn
, Media.*
FROM dbo.Media
这就是它的作用(参见 rn 列)
| rn | MediaID | MediaTypeID | Name | ReleaseID |
|----|---------|-------------|-------------------------------------------------------------------------------------|-----------|
| 1 | 2 | 2 | Movie | 2 |
| 2 | 3 | 1 | Movie | 2 |
| 1 | 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 2 | 13 | 1 | Funky Monkey; Osmosis Jones | 6 |
| 1 | 17 | 3 | Movie | 8 |
| 1 | 620 | 1 | Movie | 463 |
| 1 | 726 | 1 | Movie | 534 |
| 1 | 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
| 2 | 808 | 1 | Frosty the Snowman; Frosty Returns | 571 |
| 3 | 809 | 1 | Santa Claus is Comin' to Town!; Mr. Magoo's Christmas Carol; The Little Drummer Boy | 571 |
| 4 | 810 | 4 | Tracks 1-7 | 571 |
现在只保留 rn 列中有 1 的那些行:
| rn | MediaID | MediaTypeID | Name | ReleaseID |
|----|---------|-------------|-------------------------------------------------------|-----------|
| 1 | 2 | 2 | Movie | 2 |
| 1 | 12 | 1 | Space Jam; Looney Tunes: Back in Action | 6 |
| 1 | 17 | 3 | Movie | 8 |
| 1 | 620 | 1 | Movie | 463 |
| 1 | 726 | 1 | Movie | 534 |
| 1 | 807 | 1 | Rudolph the Red-Nosed Reindeer; Cricket on the Hearth | 571 |
然后加入 那些行 到 Releases 和 MediaType
宾果
=想要的结果。
不难,真的不难。您真的会想要了解这些 window 功能,因为它们可以解决大量问题。