SQL:从视图

时间:2017-11-01 22:24:48

标签: sql-server sql-view aggregates

我有三个SQL表:Release(表示电影的发布),Media(表示这些版本中的各个可录制媒体;即蓝光/ DVD组合,Media中有两行,一张Blu-ray和一张DVD,指向Release)和MediaType中的同一行(定义了蓝光,DVD, VHS等)。 Release / MediaMediaType / Media之间存在一对多关系,其中Media位于"很多& #34;这两种关系的一面。我有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获取与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       |
+-----------+----------------------------------------+-------------+-------+---------+---------------+--------------+----------------+

这是最后一个问题。

4 个答案:

答案 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      |

Demo available at SQLFiddle

答案 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

宾果

=想要的结果。

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