【问题标题】:Create a query to get data for unmatched records in SQL?创建查询以获取 SQL 中不匹配记录的数据?
【发布时间】:2020-05-19 19:57:29
【问题描述】:

我有两张表t1,t2 如下:

t1

[date]      col1  col3  col4
13-05-2020   xyz   ttx  1
16-05-2020   xyz   abc  5
15-05-2019   xyz   abc  2
11-05-2019   xyz   ttx  3
19-05-2020   xyx   abc  4

t2

[date]          col1
14-05-2019      ttx 
18-05-2020      abc
19-05-2020      abc

我正在尝试将t2 记录与t1 表匹配。如果匹配,则应返回匹配的记录。 如果它不匹配,那么我们需要检查t1 中的先前可用日期并使用匹配日期更新t2。 如果没有匹配的记录或 null 它应该抛出异常。

匹配标准是t2 中的datecol1 分别对应于t1 中的datecol3

预期输出

[date]          col1
11-05-2019      ttx
16-05-2020      abc
19-05-2020      abc

我正在尝试通过在临时表中获取不匹配的记录,然后循环获取t1 中可用的先前日期,但坚持使用逻辑。任何提示我们如何实现它?

create table #temp(
Id INT IDENTITY(1,1),
[date] DATE,
col1 varchar(3)
)

INSERT   INTO #temp
SELECT [date],col1
FROM t2
WHERE [date] NOT IN
    (SELECT [date] 
     FROM t1)
     AND col1 NOT IN(SELECT col3
     FROM t1)


DECLARE @count INT;
DECLARE @id INT=1;
SELECT @count=COUNT(*) FROM #temp
DECLARE @tempdate DATE;

WHILE (@count >0 )
BEGIN
SELECT @tempdate=date FROM #temp WHERE Id=@id

WHILE   --
--logic to get the matched date record

SET @count=@count-1
SET @id=@id+1
END

【问题讨论】:

  • 我不清楚您是否需要更新或插入。请说明您想要的结果。
  • @GordonLinoff 实际上,如果匹配,我需要匹配的记录,否则需要更新日期,它与 t1 中的先前日期匹配。更新了预期的输出。

标签: sql sql-server tsql


【解决方案1】:

准备数据的脚本:

CREATE TABLE t1 (
  [date] datetime,
  col1 varchar(50),
  col3 varchar(50),
  col4 numeric(18,6)
);

CREATE TABLE t2 (
  [date] datetime,
  col1 varchar(50)
);

INSERT INTO t1 ([date], col1, col3, col4) VALUES ('2020-05-12', 'xyz', 'ttx',  1)
INSERT INTO t1 ([date], col1, col3, col4) VALUES ('2020-05-16', 'xyz', 'abc',  5)
INSERT INTO t1 ([date], col1, col3, col4) VALUES ('2019-05-15', 'xyz', 'abc',  2)
INSERT INTO t1 ([date], col1, col3, col4) VALUES ('2019-05-11', 'xyz', 'ttx',  3)
INSERT INTO t1 ([date], col1, col3, col4) VALUES ('2020-05-19', 'xyx', 'abc',  4)


INSERT INTO t2 ([date], col1) VALUES ('2020-05-14', 'ttx')
INSERT INTO t2 ([date], col1) VALUES ('2020-05-18', 'abc')
INSERT INTO t2 ([date], col1) VALUES ('2020-05-19', 'abc')

首先,让我们选择所需的输出:

SELECT 
  (SELECT TOP 1 t1.[date]
     FROM t1
    WHERE t1.col3 = t2.col1
      AND t2.[date] >= t1.[date]
    ORDER BY 1 DESC) [date],
  t2.col1
FROM t2

说明:我们从 t2 中选择行并从 t1 中的匹配记录中选择日期,我们通过[date] 条件(t2.[date] >= t1.[date])对其进行限制,因此我们会按照您的要求获得匹配日期或之前的可用日期。

使用 OUTER APPLY 也可以做到这一点

SELECT t1_.[date], t2.col1
  FROM t2
  OUTER APPLY (SELECT TOP 1 t1.[date]
                 FROM t1 WHERE t1.col3 = t2.col1
                           AND t2.[date] >= t1.[date]
                ORDER BY 1 DESC) t1_

注意:您必须处理 NULL 值,尚不清楚该怎么做。 选项可能是:忽略或使用它们来删除 t2 中的记录 - 由您决定如何使用它。

现在,至于更新 - OUTER APPLY 形式的查询在这里更有用 - 基于它您可以编写:

UPDATE t2
   SET [date] = t1_.[date]
  FROM t2
  OUTER APPLY (SELECT TOP 1 t1.[date]
                 FROM t1 WHERE t1.col3 = t2.col1
                          AND t2.[date] >= t1.[date]
                ORDER BY 1 DESC) t1_

再次,小心使用空值。您可以将 OUTER APPLY 替换为 CROSS APPLY,这样会忽略空值(如果没有匹配的记录,即使之前的日期也不会更新 t2 中的行)。

如果您想检查空值并引发错误,请将其放在脚本的开头:

IF EXISTS (
     SELECT 1
       FROM t2
      WHERE NOT EXISTS (
                  SELECT 1
                    FROM t1
                   WHERE t2.[date] >= t1.[date]
                     AND t1.col3 = t2.col1
                )
           )
  RAISERROR (N'No value in t2, which match date or prior date in t1', 16, 1)

您可以使用

来调试数据的输出
 SELECT *
   FROM t2
  WHERE NOT EXISTS (
             SELECT 1
               FROM t1
              WHERE t2.[date] >= t1.[date]
                AND t1.col3 = t2.col1
           )
      )

【讨论】:

  • 太棒了 :) 是的,你对空值是正确的,如果有空值或没有匹配的记录。理想情况下它应该通过异常。我们可以在这里做。我已经更新了问题?谢谢!
  • 这对你有用吗? ``` IF EXISTS (SELECT * FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t1 WHERE t2.[date] >= t1.[date] AND t1.col3 = t2.col1)) RAISERROR (N'No value in t2, t1', 16, 1) ``` 我更新了我的答案 - 请参阅它的末尾。
【解决方案2】:

我正在尝试将 t2 记录与 t1 表匹配。如果匹配,则应返回匹配的记录。如果它不匹配,那么我们需要检查 t1 中的先前可用日期并使用匹配的日期更新 t2。

这是你想要的吗?

select t2.*, t1.date as new_date
from t2 outer apply
     (select top (1) t1.*
      from t1
      where t1.col3 = t2.col3 and t1.date <= t2.date
      order by t1.date desc
     ) t1;

如果你想要update,那么:

with toupdate as (
      select t2.*, t1.date as new_date
      from t2 outer apply
           (select top (1) t1.*
            from t1
            where t1.col3 = t2.col3 and t1.date <= t2.date
            order by t1.date desc
           ) t1
     )
update toupdate
     set date = new_date
     where new_date <> date;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-21
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多