为什么我的数据库结构和 SELECT 操作会生成 NULL?

zui*_*iqo 1 trigger sql-server-2008 sql-server import csv

我对数据库问题没有太多经验,所以请原谅文字墙,我相信上下文对于理解问题和目标很重要。


我每天都会从另一个系统收到一个 CSV 文件,我希望将其保留在 Microsoft SQL Server 上运行的数据库中。为了实现这一点,我每天安排一个 PowerShell 脚本,它使用 bcp 实用程序将 CSV ( accounts.csv ) “加载”到accounts_stage具有 CSV 文件“精确”布局的表 ( ) 中。此外,我将时间戳“写入”到另一个表 ( import_stage) 中。该accounts_stage表具有触发器集,并且 bcp 配置为触发该触发器。

导入完成后,我想“规范化”数据。对于一个基本示例,假设这仅涉及合同编号(在 CSV 文件中名为“Vnr”的字段),它是一个字符串。我有另一个表 ( contracts),它被触发器填充:

INSERT INTO dzp.contractid(vnr)
SELECT DISTINCT
    a.Vnr
FROM dzp.accounts_stage a
WHERE NOT EXISTS(
    SELECT id.vnr
    FROM dzp.contractid id
)
Run Code Online (Sandbox Code Playgroud)

这应该并且似乎完成了将所有导入到表中的合同编号contractidscontractids.contractId是 BIGINT PRIMARY KEY、IDENTITY 和自动增量。

我将导入元数据添加到我的表中,如下所示:

   CREATE TABLE #IMPORTMETADATA
            ([importid] bigint
            ,[generated_timestamp] datetime
            ,[imported_timestamp] datetime
            )
    INSERT INTO #IMPORTMETADATA
        SELECT TOP 1 [importid], [timestamp_import], [generated_timestamp]         
    FROM
            [QGTAA].[dzp].[import]
        ORDER BY
            [timestamp_import] DESC
Run Code Online (Sandbox Code Playgroud)

接下来,触发器应该 INSERT the data FROM accounts_stageINTO accounts,以便contractId替换(从原始字符串表示到contracts表的 PRIMARY KEY )。

INSERT INTO [dzp].[accounts]
      ([Udnr]
      ,[ContractId]
      -- snip
      ,[generated_timestamp]
      ,[importid]
      )
SELECT 
    a.[Udnr], 
    cid.contractId, 
    -- snip
    meta.[generated_timestamp], 
    meta.[importid]
FROM [QGTAA].[dzp].[accounts_stage] a
LEFT JOIN dzp.contractid cid ON cid.vnr = a.Vnr
CROSS JOIN #IMPORTMETADATA meta
Run Code Online (Sandbox Code Playgroud)

但是,这最后一步失败了,因为最后一个块中的 SELECT 操作产生了contractIdIS NULL 的行,这是我没想到的。现在我相信问题出在 LEFT JOIN 的某个地方,但我不确定为什么。

问题

  1. 有人可以为我指出这个特定问题的正确方向吗?

  2. 我对数据库没有太多经验,这甚至是实现我想要的东西的理智方式,还是完全疯狂的方法?有没有更好的办法?

谢谢!

Lam*_*mak 6

你的第一个有问题NOT EXISTS。让我们来看看您当前的查询:

INSERT INTO dzp.contractid(vnr)
SELECT DISTINCT
    a.Vnr
FROM dzp.accounts_stage a
WHERE NOT EXISTS(
    SELECT id.vnr
    FROM dzp.contractid id
)
Run Code Online (Sandbox Code Playgroud)

所以,这里发生的事情是,NOT EXISTS您正在使用的dzp.contractid表为空时才会返回 true 。一旦它有一行(或更多),主表的每一行NOT EXISTS都会返回false,因为SELECT id.vnr FROM dzp.contractid有一个结果集,你最终会在你的表中插入重复的值。

您需要做的是将此子查询与主表相关联:

INSERT INTO dzp.contractid(vnr)
SELECT DISTINCT
    a.Vnr
FROM dzp.accounts_stage a
WHERE NOT EXISTS(
    SELECT id.vnr
    FROM dzp.contractid id
    WHERE id.vnr = a.vnr
);
Run Code Online (Sandbox Code Playgroud)

此外,CROSS JOIN来自最新导入的数据对我来说没有多大意义,而且您没有检查数据是否已经存在于accounts表中这一事实也没有意义。