MS SQL Server-匹配表及其不相关的记录

时间:2018-12-23 20:58:10

标签: sql sql-server sql-server-2008

这可能比我想像的更普遍,但是几个月来,我一直在全力以赴,全力以赴。

两个表由完全不相关的系统提供有关相同内容的信息。但是他们为此使用了不同的标识符,我想找到一种方法将这些表合并为一个表,使A中的每个记录都与B中“最等效”的记录匹配。

两个数据库都是这样的:

A.sessionID     A.itemSeq   A.dateSessionStart
1870            32          2017-12-20 16:00:00     
1871            55          2017-12-23 17:00:00
1871            56          2017-12-23 17:00:00
1871            57          2017-12-23 17:00:00
1873            24          2018-01-05 15:00:00
1873            25          2018-01-05 15:00:00
1878            36          2018-01-12 15:30:00



B.sessionID     B.itemID    B.dateItem
520             1           2017-12-20 16:04:32     
522             1           2017-12-23 17:15:04
522             2           2017-12-23 17:32:26

523             2           2018-01-05 15:41:06
523             3           2018-01-05 16:02:21
524             1           2018-01-12 15:37:55

这是我想获得的表/视图的一部分:

A.sessionID     B.sessionID     A.itemSeq       B.itemID        A.dateSessionStart      B.dateItem
1870            520             32              1               2017-12-20 16:00:00     2017-12-20 16:04:32 
1871            522             55              1               2017-12-23 17:00:00     2017-12-23 17:15:04
1871            522             56              2               2017-12-23 17:00:00     2017-12-23 17:32:04
1871            522             57              NULL            2017-12-23 17:00:00     NULL
1873            523             24              2               2018-01-05 15:00:00     2018-01-05 15:41:06
1873            523             25              3               2018-01-05 15:00:00     2018-01-05 16:02:21
1878            524             36              1               2018-01-12 15:30:00     2018-01-12 15:37:55

似乎每个表中的日期和顺序可能允许相似的某种关系。但是:

  • 不能保证B中有足够的记录来匹配A中的记录,反之亦然。这就是我试图通过B中缺少的2018-12-23第三记录来显示的内容。 A中也有一些“丢失的记录”。实际上,两个表都具有绝对疯狂的日期记录(我猜是自由输入)。
  • 两个表都使用顺序ID,但规则不同。

我将把我在SQL查询中的知识描述为基础到中级。我试图在SELECT下创建一个子查询,在两个表的日期时间之间通过DATEDIFF进行匹配,在我所拥有的所有SQL书籍中寻找一个示例,在这里寻找类似的问题...但是到目前为止我没有成功。

谢谢!

Fabricio Rocha

巴西巴西利亚

1 个答案:

答案 0 :(得分:1)

您遇到的问题是,您已将所有这些数据加载到RELATIONAL数据库管理系统中;通过明确定义表之间的关系来工作的设备

您没有明确定义的关系

据我所知,您断言“每个系统中序列ID中项目的顺序大致相同,而时间也大致相同”

好吧,所以让我们假设这些系统都注意到播客的发生时间,并且其中一个系统的时钟有问题,只能报告小时,但它是可以保持时间的正常工作

假设您断言b的16:02相当于a的15:00,但是b的16:04相当于16:00,看来B的时钟比A的时钟早3分钟。来自A

让我们将这些数据转换为相关内容:

SELECT * FROM
(
  SELECT
    dateSessionStart,
    ROW_NUMBER() OVER(PARTITION BY dateSessionStart ORDER BY sessionId, itemSeq) rn
  FROM a
) a
FULL OUTER JOIN
(
  SELECT
    DATE_ADD(hour, HOUR(adj), CAST(CAST(adj as DATE) as DATETIME)) as dateSessionStart,
    ROW_NUMBER() OVER(PARTITION BY CAST(adj as DATE), HOUR(adj) ORDER BY sessionid, itemid) rn
  FROM(SELECT *, DATEADD(minute, -3, dateItem) adj FROM b) b
) b
ON a.dateSessionStart = b.dateSessionStart and a.rn = b.rn

如果您想获得更多详细信息,请单独运行子查询,但基本上,该查询将b记录的时间分别调回3分钟,然后通过将时间中的小时数添加到日期(午夜)来去除分钟和秒数

另外,但使用这些已调整的小时精度时间,使用row_number建立一个递增计数器。每小时变化时,计数器从1重新开始。计数器按其他顺序ID的顺序递增。因此,我们不在乎序列ID是否相等,我们只是使用它们来定义创建伪连接密钥的顺序。联接关系是在小时数精确的时间加上重新启动的计数器

上建立的

请注意,ghisb是在没有测试的情况下写在手机上的-可能会有小的错别字/语法错误,缺少括号等-让我知道您在运行它时遇到的任何错误,我可以提供帮助,但我很忙的一天,请随时对自己进行研究,如果修复它们,建议对我的答案进行修改

分区并不难;可以将它们视为一个单独的分组查询,该查询会自动重新加入主数据:

SELECT name, age, city, AVG(age) OVER(PARTITION BY city) FROM t

SELECT name, age, city, avgagecity 
FROM
  t
  INNER JOIN
  (SELECT city, AVG(age) as avgagecity FROM t GROUP BY city) c on c.city = t.city

以上两个查询在概念上是相同的;在其中一项中,我们按城市分组并平均年龄,然后将其加入主表。瞧

另一个我们要求数据库按城市划分数据,平均年龄。数据库将隐式地自动加入其bucket of city:avgage。当t.city是“ San Fran”时,db进入其所在的城市,查找san fran,拉高平均年龄,将其粘贴在行上

PARTITION BY在这里实际上是GROUP BY x JOIN x

对于顺序很重要的事情,例如row_number,出于相当明显的原因,必须使用ORDER BY。在这类查询中,PARTITION BY用于划分结果,但请注意,由于row_number不是聚合操作,因此没有任何分组。在这里,在有序操作(根本不需要分区)中,任何分区都会指定何时重新开始,就好像数据在新的计数组中一样。其他一些常见的有序操作是RANK和DENSE_RANK。像排数一样,但是它们指的是获胜的地方,所以值是相等的(一场比赛,一人在3:59赢得一英里,然后两个人在四分钟内跑了一英里。他们被排在第二位。RANK跳过如果人数并列,则数字等于1,等于2、2、2、4(没有第3位,因为并列第2位而被跳过。如果3个人并列,则4第4位将被跳过等)。DENSE_RANK不跳过