我有三个SQL表:Release
(表示电影的发布),Media
(表示这些版本中的各个可录制媒体;即蓝光/ DVD组合,Media
中有两行,一张Blu-ray和一张DVD,指向Release
)和MediaType
中的同一行(定义了蓝光,DVD, VHS等)。 Release
/ Media
和MediaType
/ Media
之间存在一对多关系,其中Media
位于"很多& #34;这两种关系的一面。我有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
表中首先出现的该版本相关联的媒体的ID(即如果一个版本有两个与之关联的DVD,它将获得一个ID值较低的DVD。本专栏本身并不实用;反过来,我想要做的是获得与MediaType
相关联的Media
。换句话说,我想要一个列,其中显示附加到每个MediaType
的第一个Media
的{{1}}。之后的列Release
应该这样做,但它会在与FirstMediaType
相关联的所有MediaType
中获得Media
并选择一个Release
按字母顺序排在第一位 - 这意味着蓝光将始终优先于DVD(这很好),但音频CD将始终优先于其他所有内容(这不是很好)。
如何在此视图中获取FirstMediaType
列,以获取MediaType
中标识的媒体的FirstMediaID
?
更新:以下是表格,列和一些示例行。
来自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 |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+
这是最后一个问题。
答案 0 :(得分:1)
我最终找到了一种简单的方法来做我想做的事。它并不像Used_By_Already的答案那样花哨(据我所知,它最终会起作用)并且可能在某处破坏了SQL最佳实践规则,但它更容易理解和维护 - 至少对于我的新手大脑来说。 / p>
由于问题是试图让视图使用它在连接中计算的聚合列,我只是将两步操作分成两个视图。 vReleasePre
包含我在原始查询中列出的所有列,但FirstMediaType
除外。 vRelease
现在只需从vReleasePre
获取所有列,然后添加FirstMediaType
,其结尾处的连接值为LEFT OUTER JOIN dbo.vMedia ON dbo.vReleasePre.FirstMediaID = dbo.vMedia.MediaID
,其中vMedia
为包含Media
的所有列以及MediaType
列(我已经有vMedia
的列)的视图。
由于这个数据库是通过实体框架在ASP.NET MVC Web应用程序中使用的,并且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
答案 1 :(得分:0)
最简单的方法是在MediaType
上的FirstMediaId = MediaType.MediaId
表中添加另一个联接
;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
答案 2 :(得分:0)
一种非常方便的技术可以返回与“First”,“Last”,“Earliest”,“Latest”等需求相关的整行,使用row_number() over()
。在这里,您需要“第一种媒体类型”,因此它与此相关。
正如您将在下面的查询中看到的那样,连接[Media]表将替换为包含行数计算的子查询。在这里,我们partition by
ReleaseID 和order by
MediaID ,因此,对于每个 ReleaseID,第一行将是最低的MediaID值。然后,在对此派生表的连接中,添加了一个额外条件,仅考虑行号为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 |
答案 3 :(得分:0)
对于新手大脑,这是我使用的子查询
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 列中的那些行:
| 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
=想要的结果。
不难,真的不难。你真的想要了解这些窗口函数,因为它们可以解决大量问题。