Ошибка TSQL CTE: неверный синтаксис рядом с ')' - PullRequest
1 голос
/ 01 декабря 2011

Я разрабатываю хранимый процесс TSQL с использованием SSMS 2008 и получаю вышеуказанную ошибку при создании CTE. Я хочу добавить логику к этому SP, чтобы она возвращалась каждый день, а не только дни с данными. Как мне это сделать? Вот мой SP до сих пор:

ALTER Proc [dbo].[rpt_rd_CensusWithChart]
   @program uniqueidentifier = NULL,
   @office uniqueidentifier = NULL
AS
DECLARE @a_date datetime
SET @a_date = case when MONTH(GETDATE()) >= 7 THEN '7/1/' + CAST(YEAR(GETDATE()) AS VARCHAR(30))
ELSE '7/1/' + CAST(YEAR(GETDATE())-1 AS VARCHAR(30)) END

if exists (
    select  * from tempdb.dbo.sysobjects o    where o.xtype in ('U')  and o.id = object_id(N'tempdb..#ENROLLEES')
) DROP TABLE #ENROLLEES;
if exists (
    select  * from tempdb.dbo.sysobjects o    where o.xtype in ('U')  and o.id = object_id(N'tempdb..#DISCHARGES')
) DROP TABLE #DISCHARGES;

declare @sum_enrollment int

set @sum_enrollment =  
(select sum(1)
from enrollment_view A
join enrollment_info_expanded_view C on A.enrollment_id = C.enroll_el_id 
where
   (@office is NULL OR A.group_profile_id = @office)

   AND (@program is NULL OR A.program_info_id = @program)
and (C.pe_end_date IS NULL OR C.pe_end_date > @a_date)
AND C.pe_start_date IS NOT NULL and C.pe_start_date < @a_date)

select 
A.program_info_id as [Program code], 
A.[program_name],
A.profile_name as Facility, 
A.group_profile_id as Facility_code, 
A.people_id, 
1 as enrollment_id,

C.pe_start_date,
C.pe_end_date,
LEFT(datename(month,(C.pe_start_date)),3) as a_month,
day(C.pe_start_date) as a_day,
@sum_enrollment as sum_enrollment

into #ENROLLEES
from enrollment_view A
join enrollment_info_expanded_view C on A.enrollment_id = C.enroll_el_id 
where
   (@office is NULL OR A.group_profile_id = @office)
   AND (@program is NULL OR A.program_info_id = @program)
and (C.pe_end_date IS NULL OR C.pe_end_date > @a_date)

AND C.pe_start_date IS NOT NULL and C.pe_start_date >= @a_date

;WITH #ENROLLEES AS (
    SELECT '7/1/11' AS dt
    UNION ALL
    SELECT DATEADD(d, 1, pe_start_date) as dt
      FROM #ENROLLEES s
     WHERE DATEADD(d, 1, pe_start_date) <= '12/1/11')

1 Ответ

5 голосов
/ 02 декабря 2011

Наиболее очевидная проблема (и, вероятно, та, которая также вызывает сообщение об ошибке) - это отсутствие фактического оператора, к которому должен относиться последний CTE.Я предполагаю, что это должен быть оператор SELECT, который бы объединял набор результатов CTE с данными из таблицы #ENROLLEES.

И вот тут возникает другая проблема.Кроме того факта, что имя, начинающееся с единственного #, вряд ли рекомендуется для всего, что не является локальной временной таблицей (CTE на самом деле не является таблицей), вы также выбрали для своего CTE определенное имя, котороеуже принадлежит к существующей таблице (точнее, к уже упомянутой временной таблице #ENROLLEES) и к той, из которой вы собираетесь получать данные.Вам определенно не следует использовать имя существующей таблицы для CTE, иначе вы не сможете присоединить ее к CTE из-за конфликта имен.

Также, на основании ее кода, последний CTEпредставляет незаконченную реализацию логики, которую вы хотите добавить в SP.Я могу предложить некоторую идею, но прежде чем я продолжу, я бы хотел, чтобы вы поняли, что на самом деле в вашем посте есть два разных запроса.Первый - найти причину сообщения об ошибке, другой - код новой логики.Как правило, вам, вероятно, лучше разделить такие запросы на отдельные вопросы, и поэтому, возможно, вы тоже в этом случае.

В любом случае, вот мое предложение:

  • полный список дат, которые вы хотите учесть в результирующем наборе (для этого будет использоваться CTE);

  • объедините этот список слева и выберите таблицу #ENROLLEESданные для существующих дат и некоторые значения по умолчанию или NULL для несуществующих.

Может быть реализовано так:

… /* all your code up until the last WITH */
;
WITH cte AS (
  SELECT CAST('7/1/11' AS date) AS dt
  UNION ALL
  SELECT DATEADD(d, 1, dt) as dt
  FROM cte
  WHERE dt < '12/1/11'
)
SELECT
  cte.dt,
  tmp.[Program code],
  tmp.[program_name],
  … /* other columns as necessary; you might also consider
       enveloping some or all of the "tmp" columns in ISNULLs,
       like in

         ISNULL(tmp.[Program code], '(none)') AS [Program code]

       to provide default values for absent data */
FROM cte
  LEFT JOIN #ENROLLEES tmp ON cte.dt = tmp.pe_start_date
;
...