连接缺少值的 SQL 视图

Posted

技术标签:

【中文标题】连接缺少值的 SQL 视图【英文标题】:Joining SQL Views with Missing Values 【发布时间】:2013-01-28 18:45:41 【问题描述】:

我在两个不同的服务器上有两个视图。

这些视图输出名称、月份、计数

一个人(Joe 用户)可能只有 7 月、8 月的一个视图,所以它会显示如下

Joe User July 19
Joe User August 28

下一个视图他们可能有更多

Joe User May 20
Joe User June 98
Joe User July 18
Joy User August 24

我想让输出显示的是这个。

Joe User January 0 0
Joe User February 0 0
Joe User March 0 0
Joe User April 0 0
Joe User May 20 0
Joe User June 98 0 
Joe User July 18 19
Joe User August 24 28
Joe User September 0 0
Joe User October 0 0
Joe User November 0 0
Joe User December 0 0

我的问题是如何填充月份,即使它们没有值?然后加入我的价值观。

更新:

通过以下示例,我得到了非常相似的结果。这是我尝试在不将名称添加到 WHERE 的情况下运行它时得到的结果。

Joe User April 65 518
Joe User April 87 518
Joe User April 52 518
Joe User April 3  518

每月重复 64 行的表格值。

【问题讨论】:

你使用的是什么关系型数据库? 什么 SQL 产品/版本(SQL Server、Oracle、mysql 等) 也许写 12 个不同的 SELECT 查询,每个月一个,然后将它们联合起来? 【参考方案1】:

你需要使用一个日期表,然后JOIN你的两个表。否则,您可以像这样在查询中创建一个:

SELECT m.month, CASE WHEN c.ccount IS NULL THEN 0 ELSE c.ccount END AS view2,
CASE WHEN b.ccount IS NULL THEN 0 ELSE b.ccount END AS view1
FROM
(SELECT 'January' AS month
  UNION ALL
  SELECT 'February'
  UNION ALL
  SELECT 'March'
  UNION ALL
  SELECT 'April'
  UNION ALL
  SELECT 'May'
  UNION ALL
  SELECT 'June'
  UNION ALL
  SELECT 'July'
  UNION ALL
  SELECT 'August'
  UNION ALL
  SELECT 'September'
  UNION ALL
  SELECT 'November'
  UNION ALL
  SELECT 'December') m
LEFT JOIN (SELECT name, month, ccount FROM view1 WHERE name = 'Joe') b ON b.month = m.month
LEFT JOIN (SELECT name, month, ccount FROM view2 WHERE name = 'Joe') c ON c.month = m.month

结果

|月 |视图2 |查看1 | ----------------------------------------- |一月 | 0 | 0 | |二月 | 0 | 0 | |三月 | 0 | 0 | |四月 | 0 | 0 | |五月 | 20 | 0 | |六月 | 98 | 0 | |七月 | 18 | 19 | |八月 | 24 | 28 | |九月 | 0 | 0 | |十一月 | 0 | 0 | |十二月 | 0 | 0 |

【讨论】:

这似乎是正确的道路。我试过了,它非常接近。现在的问题是我如何为所有 200 个用户运行它而不必在连接中指定名称?同样对于用户一无所有的月份,名称显示为空。 @JDRoberson 有用吗?那么这个“我在两个不同的服务器上有两个视图”呢? @HamletHakobyan 如果服务器已链接,则无需打开新连接。 它们是链接的,我可以获取所有数据,只是输出格式问题。 @JDRoberson 好的,那么我的解决方案是多余的 :) 那你就不用说不同的服务器了。【参考方案2】:
SELECT DATENAME(mm, DATEADD(mm, number, '20010101')), 
       ISNULL(v2.[count], 0), ISNULL(v1.[count], 0)
FROM master..spt_values v LEFT JOIN view1 v1 ON DATENAME(mm, DATEADD(mm, v.number, '20010101')) = v1.[month] AND v1.name = 'Joe User'
                          LEFT JOIN view2 v2 ON DATENAME(mm, DATEADD(mm, v.number, '20010101')) = v2.[month] AND v2.name = 'Joe User'
WHERE v.type = 'P' AND v.number < 12

SQLFiddle上的演示

更新

SELECT *
FROM
(
 SELECT v1.name
 FROM view1 v1
 UNION
 SELECT v2.name
 FROM view2 v2
 ) u CROSS APPLY (
                  SELECT DATENAME(mm, DATEADD(mm, number, '20010101')) AS [month], 
                         ISNULL(v2.[count], 0) AS [count1], ISNULL(v1.[count], 0) AS [count2]                       
                  FROM master..spt_values v 
                    LEFT JOIN view1 v1 ON DATENAME(mm, DATEADD(mm, v.number, '20010101')) = v1.[month] AND v1.name = u.name
                    LEFT JOIN view2 v2 ON DATENAME(mm, DATEADD(mm, v.number, '20010101')) = v2.[month] AND v2.name = u.name
                  WHERE v.type = 'P' AND v.number < 12
                  ) o

SQLFiddle 上的新演示

【讨论】:

也试过了。输出不一样。在您的演示中,将另一个用户添加到第二个表并给他 24。然后再次运行它。它提取了一个对他来说不存在的值。 我在 JOIN 操作中添加条件;) 我可以让它与 1 个用户一起工作。问题是有 200 个用户,我不想编辑查询 200 次。 但是 sqlfiddle 工作没有错误。!?!具体是什么错误 好的,所以我今天早上搞砸了它并修复了整理错误。这很完美!我需要对其中一些进行一些研究,但我欠你一杯啤酒!【参考方案3】:

首先您必须创建链接服务器或使用OPENROWSET。 试试这个OPENROWSET

;WITH Months
AS
(
    SELECT 1 m, DATENAME(mm, '20000101') MN
    UNION ALL
    SELECT m+1, DATENAME(mm, DATEADD(m, m, '20000101')) MN
    FROM Months
    WHERE m < 12
)
SELECT
   COALESCE(V1.nmae, V2.name) Name, 
   M.MN [Month], 
   ISNULL(V1.count, 0) Count1, 
   ISNULL(V2.count, 0) Count12 
FROM Months M
    LEFT JOIN ViewOnCurrentServer V1
        ON M.MN = V1.[month]
    LEFT JOIN
         OPENROWSET('SQLNCLI', 'Server=YouServerName;Trusted_Connection=yes;',
                    'SELECT name, month, count
                     FROM DBName.SchemeName.ViewOnAnotherServer') V2
       ON M.MN = V2.[month]
WHERE COALESCE(V1.nmae, V2.name) = 'Joe User'

或者如果您使用链接服务器,则使用:

;WITH Months
AS
(
    SELECT 1 m, DATENAME(mm, '20000101') MN
    UNION ALL
    SELECT m+1, DATENAME(mm, DATEADD(m, m, '20000101')) MN
    FROM Months
    WHERE m < 12
)
SELECT
   COALESCE(V1.nmae, V2.name) Name, 
   M.MN [Month], 
   ISNULL(V1.count, 0) Count1, 
   ISNULL(V2.count, 0) Count12 
FROM Months M
    LEFT JOIN ViewOnCurrentServer V1
        ON M.MN = V1.[month]
    LEFT JOIN
         ViewOnLinkedServer V2
       ON M.MN = V2.[month]
WHERE COALESCE(V1.nmae, V2.name) = 'Joe User'

【讨论】:

尝试这个,他们有不同的排序规则,所以我得到一个错误。我将在此语句中的何处放置 COLLATE DATABASE_DEFAULT 试试这个:WHERE COALESCE(V1.nmae, V2.name) COLLATE DATABASE_DEFAULT= 'Joe User' COLLATE DATABASE_DEFAULT 我认为您也需要在 JOIN 条件中添加它。 无法解决 SELECT 语句中第 1 列的排序规则冲突。 试试这个:COALESCE(V1.name COLLATE DATABASE_DEFAULT, V2.name COLLATE DATABASE_DEFAULT)

以上是关于连接缺少值的 SQL 视图的主要内容,如果未能解决你的问题,请参考以下文章

SQL之复杂查询与视图

SQL之复杂查询与视图

SQL之复杂查询与视图

Sql Server 2008 中缺少全文索引系统视图

如何制定聚合不同值的 SQL Server 索引视图?

在sql server中选择具有重复值的视图的不同值