【问题标题】:Vlookups in SQLSQL中的Vlookup
【发布时间】:2020-02-17 14:50:42
【问题描述】:

我正在尝试编写一个查询,该查询将为帐户代码的每个段提取描述。表格如下:

我想要做的是让每个 CTRC 部分为匹配示例的 CTACCT 提取 CTDESC:

我的原始数据有超过 400 万行,因此我无法导出到 excel 以进行正常的 Vlookup。我只有一张包含所有这些数据的表,并且无法进行自联接以提取所有行,我一次只能做一个部分。

SELECT TOP 10
       RTRIM(a.CTACCT) AS [CTACCT],
       RTRIM(a.CTRC01) AS [CTRC01],
       NULLIF(CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02)), CONCAT(RTRIM(a.CTrc01), '-')) AS [CTRC02],
       NULLIF(CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-', RTRIM(a.CTrc03)), CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-')) AS [CTRC03],
       NULLIF(CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-', RTRIM(a.CTrc03), '-', RTRIM(a.CTrc04)), CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-', RTRIM(a.CTrc03), '-')) AS [CTRC04],
       NULLIF(CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-', RTRIM(a.CTrc03), '-', RTRIM(a.CTrc04), '-', RTRIM(a.CTrc05)), CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-', RTRIM(a.CTrc03), '-', RTRIM(a.CTrc04), '-')) AS [CTRC05],
       NULLIF(CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-', RTRIM(a.CTrc03), '-', RTRIM(a.CTrc04), '-', RTRIM(a.CTrc05), '-', RTRIM(a.CTrc06)), CONCAT(RTRIM(a.CTrc01), '-', RTRIM(a.CTrc02), '-', RTRIM(a.CTrc03), '-', RTRIM(a.CTrc04), '-', RTRIM(a.CTrc05), '-')) AS [CTRC06],
       a.CTDESC AS [CTDESC],
       a.CTSEGN AS [CTSEGN]
FROM [PSA].[dbo].[SMFD35_GLDBFA_GLPCT] a WITH (NOLOCK);

我正在使用 SQL Server。


【问题讨论】:

  • SQL 中的“VLookup”称为JOIN。另外,为什么在这里使用NOLOCK?你明白它的用途是什么意思吗?
  • 您编辑了代码阻止的表格以换取图片。这是一个倒退。
  • 数据和结果的图像几乎一文不值。 Why?
  • “我的公司也需要无锁,因为可以有多个人从数据中提取数据” 听起来你的公司需要实际实施一些索引,而不是告诉人们他们应该这样做对错误的结果保持“正常”。
  • 呃。我了解很多人。但是 NOLOCK 并不是一个神奇的快速按钮。它会做一些有趣的事情,例如随机返回丢失和/或重复的行,因此您无法重现错误。这里跳出来的另一件事是该表似乎存在一些规范化问题。当你有 CTrc01、CTrc02 之类的东西时,你就有了所谓的重复组。它违反了 1NF。

标签: sql-server join sql-server-2012 vlookup self-join


【解决方案1】:

有几种方法可以做到这一点,因为您的表中已经有了值,一种方法是从原始表中添加一个 id 字段并标记 CTRC (LevelNr) 对应于结果中的 CTACCT:

select A.CTACCT, max(B.CTRC01) AS CTRC01, 
  max(case when B.LevelNr = 1 then B.Description else null end) AS CTRC01_Description,
  max(case when A.LevelNr >=2 then B.CTRC02 else null end) AS CTRC02, 
  max(case when A.LevelNr >=2 and B.LevelNr = 2 then B.Description else null end) AS CTRC02_Description,
  max(case when A.LevelNr >=3 then B.CTRC03 else null end) AS CTRC03, 
  max(case when A.LevelNr >=3 and B.LevelNr = 3 then B.Description else null end) AS CTRC03_Description
from @MyResults A
  inner join @MyResults B on A.id = B.id
group by A.[CTACCT], A.id, A.LevelNr
order by A.[CTACCT], A.id, A.LevelNr

结果:

CT_ACCT        CTRC01 CTRC01_Description CTRC02   CTRC02_Description CTRC03        CTRC03_Description
001            001    Company            NULL     NULL               NULL          NULL
001-0000       001    Company            001-0000 Department         NULL          NULL
001-0000-0000  001    Company            001-0000 Department         001-0000-0000 Location

不过,这确实应该是关于数据库设计的讨论。如果您有单独存储每个 CTRC 值的数据,那么 STRING_AGG() 和 PIVOT 等分组函数就会发挥作用。

假设您可以使用 UNION 查询以如下状态获取数据:

id RowNr CTAcct
1  1     001
1  2     0000
1  3     0000
2  1     002
2  2     0000
2  3     0000

然后,您可以将所有帐号和描述放在一起,如下所示(STRING_AGG 更好,但 FOR XML 会为您的版本解决问题):

select [CTACCT], id, RowNr, Description
from
(
select RowNr, id,
  STUFF((SELECT '-' + [CTACCT]
    from @CTACCTS A where A.[id] = T.[id] and A.[RowNr] <= T.[RowNr]
    FOR XML PATH('')),1, 1,'') as [CTACCT]
from @CTACCTS T
) A left join @CTDESCRIPTIONS D ON A.[CTACCT] = D.[CTACCT]

结果:

CTACCT        id RowNr Description
001           1  1     Company
001-0000      1  2     Department
001-0000-0000 1  3     Location

最后,您可以执行与上述类似的操作,将事物重新组合在一起。这可能看起来像是额外的工作,但具有避免冗余的优点。

当然,您也可以执行一系列更新语句,但一般不建议在 SQL Server 中使用基于非集合的例程。

【讨论】:

    猜你喜欢
    • 2021-03-15
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多