【问题标题】:CTE values need to insert into another tableCTE 值需要插入到另一个表中
【发布时间】:2021-10-08 13:13:56
【问题描述】:

以下查询我无法将公用表表达式选择值插入另一个表。

;WITH cte AS
(
    SELECT 
        rd.reorderhistoryId,
        rd.dateCreated,
        rd.personId,
        rd.reorderId,
        rd.statusNo,
        rd.createdBy,
        r.OrganizationId
    FROM 
        (SELECT 
             MIN(reorderhistoryId) AS reorderhistoryId,
             MIN(personId) AS personId,
             reorderId
         FROM 
             reorderHistoryDetails
         GROUP BY 
             reorderId) rh 
    INNER JOIN 
        reorderHistoryDetails rd ON rd.reorderhistoryId = rh.reorderhistoryId
    INNER JOIN 
        reorderDetails r ON r.personId = rd.personId
    WHERE 
        rd.statusNo = 1059
)
SELECT DISTINCT TOP 5
    rlst.personId AS personId,
    'Start Reorder Process' AS reorderStatusType,
    1 AS productId,
    3 AS amountPaid,
    rlst.reorderId,
    rlst.OrganizationId AS orgId,
    rlst.createdBy,
    rlst.dateCreated,
    rlst.dateCreated AS timeStamp
FROM
    cte rlst
INNER JOIN 
    doctororderall d ON rlst.personId = d.personId
                     AND d.productId = 1
                     AND YEAR(rlst.dateCreated) = YEAR(d.dateCreated)
INNER JOIN 
    patientdetails pd ON pd.personId = d.personId
WHERE 
    rlst.datecreated > '2020-09-01'
    AND rlst.dateCreated <= '2021-10-06'

INSERT INTO rouletteTracking (personId, reorderStatusType, productId,
                              amountPaid, reorderId, orgId, 
                              createdBy, dateCreated, timeStamp)
SELECT *
FROM cte

我收到此错误:

消息 208,第 16 级,状态 1,第 14 行
无效的对象名称“cte”。

【问题讨论】:

  • 1.空格和换行符是“神奇”的东西;这使您可以阅读的那些不可读的代码块。 2. 分号 (;) 是语句终止符,它们位于所有语句的末尾,而不是需要的语句的开头上一个 语句被正确终止。 3.顾名思义(Common Table Expression),一个CTE就是一个表达式;如果它没有在语句中定义,则它不存在于语句的范围内。 CTE 未在您的第二个语句中定义,因此它不存在。
  • 先生,请问有什么解决方案。 @Larnu
  • 我的暗示;在语句中定义 CTE。或者,或者,将数据插入(临时)表,然后从该表中插入 SELECTINSERT
  • sir CTE 数据不为空,请问哪个语句可以给我需要修改的行。 @Larnu
  • 我没有说 CTE 是空的,我说它没有定义。 CTE 显然不会导致空结果,因为您的第一个查询返回 5 行。问题是您稍后尝试在声明中引用该 CTE,但正如我所提到的,您尚未(再次)定义该 CTE,因此您会收到错误。正如我自己和格兰特在他们的回答中所说,提示就在名称中:Common Table Expression

标签: sql sql-server


【解决方案1】:

我自己(在 cmets 中)和 Grant(在他们的回答中)都已经涵盖了这一点,但是,为了重复这一点,一个 Common Table Expression 是一个 expression。它的范围仅限于定义它的语句的范围(与其他表达式一样)。如果您正确地终止您的陈述,您会看到上面有 两个 陈述; SELECTINSERT,因此第二个中没有定义 CTE:

WITH cte AS
    (SELECT rd.reorderhistoryId,
            rd.dateCreated,
            rd.personId,
            rd.reorderId,
            rd.statusNo,
            rd.createdBy,
            r.OrganizationId
     FROM (SELECT MIN(reorderhistoryId) AS reorderhistoryId,
                  MIN(personId) AS personId,
                  reorderId
           FROM reorderHistoryDetails
           GROUP BY reorderId) rh --on d.personId=rh.personId
          INNER JOIN reorderHistoryDetails rd ON rd.reorderhistoryId = rh.reorderhistoryId
          INNER JOIN reorderDetails r ON r.personId = rd.personId
     WHERE rd.statusNo = 1059)
SELECT DISTINCT TOP 5
       rlst.personId AS personId,
       'Start Reorder Process' AS reorderStatusType,
       1 AS productId,
       3 AS amountPaid,
       rlst.reorderId,
       rlst.OrganizationId AS orgId,
       rlst.createdBy,
       rlst.dateCreated,
       rlst.dateCreated AS timeStamp
FROM cte rlst
     INNER JOIN doctororderall d ON rlst.personId = d.personId
                                AND d.productId = 1
                                AND YEAR(rlst.dateCreated) = YEAR(d.dateCreated)
     INNER JOIN patientdetails pd ON pd.personId = d.personId
WHERE rlst.datecreated > '2020-09-01'
  AND rlst.dateCreated <= '2021-10-06'; --This statement ends HERE

--New statement starts here. The CTE cte has no context here.
INSERT INTO rouletteTracking (personId,
                              reorderStatusType,
                              productId,
                              amountPaid,
                              reorderId,
                              orgId,
                              createdBy,
                              dateCreated,
                              timeStamp)
SELECT *
FROM cte;

假设您想先将 CTE 中的 SELECT TOP (5)(任意)行,然后将 CTE 中的 INSERT 整个结果集放入您的表中,我会INSERT 将数据先存入一个临时表,然后SELECTINSERT 从那个:

WITH cte AS
    (SELECT rd.reorderhistoryId,
            rd.dateCreated,
            rd.personId,
            rd.reorderId,
            rd.statusNo,
            rd.createdBy,
            r.OrganizationId
     FROM (SELECT MIN(reorderhistoryId) AS reorderhistoryId,
                  MIN(personId) AS personId,
                  reorderId
           FROM reorderHistoryDetails
           GROUP BY reorderId) rh --on d.personId=rh.personId
          INNER JOIN reorderHistoryDetails rd ON rd.reorderhistoryId = rh.reorderhistoryId
          INNER JOIN reorderDetails r ON r.personId = rd.personId
     WHERE rd.statusNo = 1059)
SELECT *
INTO #Temp
FROM cte;

SELECT DISTINCT TOP 5
       rlst.personId AS personId,
       'Start Reorder Process' AS reorderStatusType,
       1 AS productId,
       3 AS amountPaid,
       rlst.reorderId,
       rlst.OrganizationId AS orgId,
       rlst.createdBy,
       rlst.dateCreated,
       rlst.dateCreated AS timeStamp
FROM #Temp rlst
     INNER JOIN doctororderall d ON rlst.personId = d.personId
                                AND d.productId = 1
                                AND YEAR(rlst.dateCreated) = YEAR(d.dateCreated)
     INNER JOIN patientdetails pd ON pd.personId = d.personId
WHERE rlst.datecreated > '2020-09-01'
  AND rlst.dateCreated <= '2021-10-06'
ORDER BY {The Column to order by}; --This statement ends HERE

--New statement starts here. The CTE cte has no context here.
INSERT INTO rouletteTracking (personId,
                              reorderStatusType,
                              productId,
                              amountPaid,
                              reorderId,
                              orgId,
                              createdBy,
                              dateCreated,
                              timeStamp)
SELECT *
FROM #Temp;

注意:我预计最后的 INSERT 语句仍然会失败。您尝试插入timestamp 列(rowversion 的已弃用同义词);这是不允许的。

【讨论】:

  • 感谢您为我收到此错误所做的努力:Msg 208, Level 16, State 0, Line 1 Invalid object name '#Temp'。 @Larnu
  • 糟糕,应该是 SELECT ... INTO 而不是 INSERT INTO...SELECT
【解决方案2】:

公用表表达式这个名称有点误导。许多人阅读它并非常突出地看到“TABLE”一词。然后他们假设他们正在处理一种新的临时表或表变量。但是,要重点关注的词是“EXPRESSION”。

CTE 只能在定义它的语句中使用。无论如何,它不是临时存储。这只是一个查询。这就像有一个子查询来定义这样的表:

SELECT * 
FROM (SELECT * FROM dbo.MyTable) as NotaCTEButActsLikeOne

为了执行您的流程,您需要将包括您的 CTE 在内的整个 SELECT 语句移动到带有 INSERT 流程的单个语句中。

编辑:

这里。您只需移动所有内容,使其成为单个语句:

WITH
cte AS
    (SELECT rd.reorderhistoryId,
            rd.dateCreated,
            rd.personId,
            rd.reorderId,
            rd.statusNo,
            rd.createdBy,
            r.OrganizationId
     FROM (SELECT MIN(reorderhistoryId) AS reorderhistoryId,
                  MIN(personId) AS personId,
                  reorderId
           FROM reorderHistoryDetails
           GROUP BY reorderId) rh --on d.personId=rh.personId
          INNER JOIN reorderHistoryDetails rd ON rd.reorderhistoryId = rh.reorderhistoryId
          INNER JOIN reorderDetails r ON r.personId = rd.personId
     WHERE rd.statusNo = 1059)
INSERT INTO rouletteTracking (personId,
                              reorderStatusType,
                              productId,
                              amountPaid,
                              reorderId,
                              orgId,
                              createdBy,
                              dateCreated,
                              timeStamp)
SELECT DISTINCT TOP 5
       rlst.personId AS personId,
       'Start Reorder Process' AS reorderStatusType,
       1 AS productId,
       3 AS amountPaid,
       rlst.reorderId,
       rlst.OrganizationId AS orgId,
       rlst.createdBy,
       rlst.dateCreated,
       rlst.dateCreated AS timeStamp
FROM cte rlst
     INNER JOIN doctororderall d ON rlst.personId = d.personId
                                AND d.productId = 1
                                AND YEAR(rlst.dateCreated) = YEAR(d.dateCreated)
     INNER JOIN patientdetails pd ON pd.personId = d.personId
--inner join (select min(reorderhistoryId) as reorderhistoryId,min(personId) as personId,reorderId from reorderHistoryDetails where statusNo=1059 and personId=226020  group by reorderId )as  rh  on d.personId=rh.personId
--inner join reorderHistoryDetails rd on rd.reorderHistoryId=rh.reorderhistoryId and rd.statusNo=1059 
WHERE rlst.datecreated > '2020-09-01'
  AND rlst.dateCreated <= '2021-10-06';

另外,请注意,分号是语句终止符,而不是您放在 WITH 子句前面的东西。在线示例这样做,以便人们可以复制代码并编译(一种正确的方法)。但是,只要将它放在语句的末尾,一切都会正常工作,代码也不会看起来很糟糕。

【讨论】:

  • 你能写出完整的答案吗?先生。 @格兰特弗里奇
  • “网上的例子就是这样做的,这样人们可以复制代码,它会编译” 在我看来,如果你复制粘贴 CTE 例子,它不会编译(由于缺少语句终止)这不是示例的错,而是复制它的人并且没有正确编写他们之前的 SQL。如果复制它的人正确地编写了自己的 SQL,则没有“初学者”的在线示例编译得很好。 ;) 其他人代码中的语法错误不是在线示例的错。
  • 我不那样做。我有朋友这样做。我尊重他们的理由,即使我不完全同意他们。让我们面对现实吧,如果您在不了解它们如何工作并在系统中测试它们以使其正确的情况下复制和粘贴在线解决方案,那么您就是在取消之后发生的所有事情。
猜你喜欢
  • 1970-01-01
  • 2021-11-17
  • 2012-03-06
  • 2014-07-29
  • 2021-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多