0

我有三个 SQL 表:(Release代表电影的发行),Media(代表这些发行版中的各个可录制媒体;即对于蓝光/DVD 组合,将有两行Media,一个蓝光和一张 DVD,指向Release) 和MediaType(定义蓝光、DVD、VHS 等) 中的同一行。Release/MediaMediaType/存在一对多的关系,Media并且Media处于两种关系的“多”方。我有一个 , 的视图ReleasevRelease其中包含聚合函数,例如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获取与该版本相关联的媒体 ID,该版本首先出现在Media表中(即,如果一个版本有两个与之关联的 DVD,它会获取一个 ID 较低的价值)。该列本身没有用;然后,我想做的是获得MediaType与之Media相关的内容。换句话说,我想要一列显示MediaType附加Media到每个Release. 之后的列 ,FirstMediaType应该这样做,但它反而获得MediaTypeMediaRelease并选择按字母顺序排在第一位的那个——这意味着蓝光将始终优先于 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       |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+

最后一个才是问题所在。

4

4 回答 4

1

我最终找到了一种简单的方法来做我想做的事。它不像 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躺在周围了)。

由于该数据库正在通过实体框架在 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
于 2017-11-03T03:14:43.483 回答
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
于 2017-11-02T01:01:56.100 回答
0

一种非常方便的技术是使用row_number() over(). 在这里你想要“第一个媒体类型”,所以它在这里是相关的。

正如您将在以下查询中看到的,加入 [Media] 表的查询被替换为包含行号计算的子查询。这里我们partition by 使用 ReleaseIDorder 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      |

SQLFiddle 上提供的演示

于 2017-11-02T21:32:28.650 回答
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列中为 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

答对了

= 想要的结果。

不难,真的不难。您真的会想了解这些窗口函数,因为它们可以解决大量问题。

于 2017-11-03T03:37:07.357 回答