【问题标题】:Select replace and then join选择替换然后加入
【发布时间】:2019-01-16 16:27:36
【问题描述】:

我有两张表要合并。

第一个表有一个关键记录列ITEMID,其中关键记录具有后缀ITEMID_CV,并且该表包含我想要的另一列数据。第二个表有相同的键记录,但后缀不同ITEMID_PH,其余数据列。

对于第一个表,我可以使用:

SELECT 
    REPLACE (ITEMID,'CV','PH') AS ITEMID, 
    CAST (ENDDATE AS DATETIME) AS ENDDATE 
FROM PLTReports 

这给了我与第二个表相同的 ITEMID 名称。所以我在那儿。现在我不知道该怎么做是将这个结果加入到另一个表的其余部分。以下给了我一个模棱两可的列名错误。错误是: 错误--------

无法链接到外部表:意外的服务器错误:'延迟 准备无法完成。无法准备报表。 不明确的列名 'ITEMID'.'。使用事件查看器查看 PI AF 服务器日志文件以获取更多信息。

我想我可能已经接近解决这个问题了,但我真的找不到如何做到这一点的示例,而且我可能使用了错误的语法。

SELECT 
    REPLACE (ITEMID,'CV','PH') AS ITEMID, 
    CAST (ENDDATE AS DATETIME) AS ENDDATE 
FROM PLTReports 
INNER JOIN PRODUCTION_ALL ON PRODUCTION_ALL.ITEMID = PLTReports.ITEMID

有没有人有关于如何做到这一点的策略?这可能很简单,但我还没有完全到达那里。

编辑:这是用于在 PI AF 中创建链接表,我不记得它使用了什么风格的 SQL。

【问题讨论】:

  • 将 (PLTReports.ITEMID,'CV','PH') 替换为 ITEMID,
  • 您使用的是哪个DBMS 产品? “SQL”只是一种查询语言,而不是特定数据库产品的名称。请为您正在使用的数据库产品添加tag
  • 你得到的错误是 exact 查询?

标签: sql sql-server


【解决方案1】:

你几乎找到了解决方案:

SELECT 
    REPLACE (ITEMID,'CV','PH') AS ITEMID, 
    CAST (ENDDATE AS DATETIME) AS ENDDATE 
FROM PLTReports 
INNER JOIN PRODUCTION_ALL 
    ON PRODUCTION_ALL.ITEMID = REPLACE(PLTReports.ITEMID,'CV','PH')

【讨论】:

  • 在连接本身中进行这种字符串操作对性能不利。
  • 如果数据不是太复杂,那么糟糕的表现就会很明显。
  • 除非有一个大数据集,这通常是一个安全的假设。不要为不良做法找借口
  • 是的,不同的后缀很荒谬,但这是我正在尝试解决的创作者遗留问题。
  • Laserwolf :用确切的错误编辑您的问题。 @DougCoats stackoverflow.com/questions/17729365/… 您是否有基准来确保子查询连接比 Join 中的替换具有更好的性能?
【解决方案2】:

如果我理解正确,您需要在连接条件中使用REPLACE。此外,具有相同名称的字段需要前缀:

SELECT 
    PRODUCTION_ALL.* 
    CAST (PLTReports.ENDDATE AS DATETIME) AS ENDDATE 
FROM PLTReports 
INNER JOIN PRODUCTION_ALL ON PRODUCTION_ALL.ITEMID = REPLACE (PLTReports.ITEMID,'CV','PH')

【讨论】:

  • 我试过这种方式,它只返回我从第一个表中得到的两列。
  • @Laserwolf:您还想获得哪些其他专栏?基本上你只需要将它们添加到 SELECT 子句中。
  • 我想要的大部分数据都在 PRODUCTION_ALL 表中。除了键之外,PLTReports 表中只有一列数据
  • @Laserwolf :我编辑了答案以选择 PRODUCTION_ALL 的所有列(PRODUCTION_ALL.* 表示 PRODUCTION_ALL 中的所有列)。这只是演示任何列都可以选择的示例。您可能希望根据您实际想要显示的列列表对其进行调整。
【解决方案3】:

由于两个表都有一个“ITEMID”,您需要指定 REPLACE() 应该使用哪个表:

REPLACE (PLTReports.ITEMID,'CV','PH') AS ITEMID,

但我认为从你所说的你也必须调整PRODUCTION_ALL.ITEMID = PLTReports.ITEMID,因为正如你所说,

第二张表的键记录相同,但后缀不同

所以你也需要在连接条件中替换:

PRODUCTION_ALL.ITEMID = REPLACE(PLTReports.ITEMID,'CV','PH')

令人遗憾的是,这效率低下,因为必须生成来自 REPLACE 的临时未索引结果集;这就是为什么你的索引不匹配是相当不幸的。

【讨论】:

    【解决方案4】:

    如果没有你的太多意见,我认为这就是你所追求的

    SELECT
        x.ITEMID
        , x.ENDDATE
    FROM
        (
            SELECT 
                REPLACE (ITEMID,'CV','PH') AS ITEMID, 
                CAST (ENDDATE AS DATETIME) AS ENDDATE 
            FROM PLTReports 
        ) x 
    INNER JOIN PRODUCTION_ALL ON PRODUCTION_ALL.ITEMID = x.ITEMID
    

    你也可以这样做,这可能会更好

    ; with cte AS 
        (
            SELECT 
                REPLACE (ITEMID,'CV','PH') AS ITEMID, 
                CAST (ENDDATE AS DATETIME) AS ENDDATE 
            FROM PLTReports 
        )
    SELECT 
        cte.ITEMID
        , ENNDATE
        , PRODUCTION_ALL.*
    FROM cte 
        INNER JOIN PRODUCTION_ALL ON cte.ITEMID = PRODUCTION_ALL.ITEMID
    

    【讨论】:

    • 为什么是子查询?
    • @DanFarrel 比在加入本身中这样做更好,这是一种不好的做法。但是有几种不同的方法可以达到这一点
    • 老实说,如果我们真的关心性能,您根本不会使用子查询,而是在 CTE 中进行字符串操作,然后再加入。我的意思是,这实际上取决于您要输入多少打字或您想要变得多复杂。
    • @Laserwolf 在外部选择上,ITEMID 需要完全限定。我忽略了,我的错。只需在其前面加上正确的表名
    • 感谢@DougCoats,修改后的语法有效,但我仍然只从 cte 获取两列。它不会返回任何我想从 PRODUCTION_ALL 表中加入的数据。
    猜你喜欢
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 2014-10-01
    • 2018-09-01
    • 2017-08-10
    • 2021-07-04
    • 1970-01-01
    相关资源
    最近更新 更多