Home > database >  CTE values need to insert into another table
CTE values need to insert into another table

Time:10-09

Below query i am not able to insert common table expression select values into another table.

;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

I'm getting this error:

Msg 208, Level 16, State 1, Line 14
Invalid object name 'cte'.

CodePudding user response:

Both myself (in the comments) and Grant (in their answer) has already covered this, however, to repeat this a Common Table Expression is an expression. It's scope is limited to the scope of the statement it is define in (like other expressions). If you properly terminate your statements you'll see you have two statements above; a SELECT and an INSERT, and thus the CTE isn't defined in the second:

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;

Assuming you want to SELECT the TOP (5) (arbitrary) rows first from the CTE first, and then INSERT the entire result set from the CTE into your table afterwards, I would INSERT the data into a temporary table first, and then SELECT and INSERT from that:

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;

Note: I expect the INSERT statement at the end to still fail. You attempt to insert into a timestamp column (a deprecated synonym for rowversion); that isn't allowed.

CodePudding user response:

The name Common Table Expression is a bit misleading. Many people read it and see the word "TABLE" very prominently. They then assume that they're dealing with a new kind of temporary table or table variable. However, the word to focus on is "EXPRESSION".

A CTE is only useable within the statement that defines it. It's not, in any way, temporary storage. It's simply a query. It's like having a sub-query to define a table like this:

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

In order to do your process, you need to move the entire SELECT statement including your CTE into a single statement with the INSERT process.

EDIT:

Here. You just move everything so that it's a single statement:

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';

Also, please, the semi-colon is a statement terminator, not something you put in front of the WITH clause. Examples on line do that so that people can copy the code and it will compile (a righteous approach). However, just putting it at the end of your statements, everything will work and the code won't look awful.

  • Related